Usage

The basic usage pattern of feature-u is to:

  1. Choose the Aspects that you will need, based on your selected frameworks (i.e. your run-time stack). This extends the aspect properties accepted by the Feature object (for example: Feature.reducer for redux, or Feature.logic for redux-logic).

    Typically these Aspects are packaged separately in NPM, although you can create your own Aspects (if needed).

  2. Organize your app into features.

    • Each feature should be located in it's own directory.

    • How you break your app up into features will take some time and thought. There are many ways to approach this from a design perspective.

    • Each feature will promote it's aspect content through a Feature object (using createFeature()).

  3. Your mainline starts the app by invoking launchApp(), passing all Aspects and Features.

Easy Peasy!!

Directory Structure

Here is a sample directory structure of an app that uses feature-u:

src/
  app.js              ... launches app using launchApp()

  feature/
    index.js          ... accumulate/promote all app Feature objects

    featureA/         ... an app feature
      actions.js
      appDidStart.js
      appWillStart.js
      comp/
        ScreenA1.js
        ScreenA2.js
      index.js        ... promotes featureA object using createFeature()
      logic.js
      reducer.js
      route.js

    featureB/         ... another app feature
      ...

  util/               ... common utilities used across all features
    ...

Each feature is located in it's own directory, containing it's aspects (actions, reducers, components, routes, logic, etc.).

Feature Object

Each feature promotes it's aspect content through a Feature object (using createFeature()).

src/feature/featureA/index.js

import {createFeature}  from 'feature-u';
import reducer          from './state';
import logic            from './logic';
import route            from './route';
import appWillStart     from './appWillStart';
import appDidStart      from './appDidStart';

export default createFeature({
  name:     'featureA',
  enabled:  true,

  publicFace: {
    api: {
      open:  () => ... implementation omitted,
      close: () => ... implementation omitted,
    },
  },

  reducer,
  logic,
  route,

  appWillStart,
  appDidStart,
});

We will fill in more detail a bit later, but for now notice that the feature is conveying reducers, logic modules, routes, and does some type of initialization (appWillStart/appDidStart). It also promotes a publicFace (open/close) that can be used by other features (i.e. the feature's Public API).

launchApp()

In feature-u the application mainline is very simple and generic. There is no real app-specific code in it ... not even any global initialization! That is because each feature can inject their own app-specific constructs!! The mainline merely accumulates the Aspects and Features, and starts the app by invoking launchApp():

src/app.js

import ReactDOM          from 'react-dom';
import {launchApp}       from 'feature-u';
import {reducerAspect}   from 'feature-redux';
import {logicAspect}     from 'feature-redux-logic';
import {routeAspect}     from 'feature-router';
import features          from './feature';

// launch our app, exposing the App object (facilitating cross-feature communication)
export default launchApp({           // *4*

  aspects: [                         // *1*
    reducerAspect, // redux          ... extending: Feature.reducer
    logicAspect,   // redux-logic    ... extending: Feature.logic
    routeAspect,   // Feature Routes ... extending: Feature.route
  ],

  features,                          // *2*

  registerRootAppElm(rootAppElm) {   // *3*
    ReactDOM.render(rootAppElm,
                    getElementById('myAppRoot'));
  }
});

Here are some important points of interest (match the numbers to *n* in the code above):

  1. the supplied Aspects (pulled from separate npm packages) reflect the frameworks of our run-time stack (in our example redux, redux-logic, and feature-router) and extend the acceptable Feature properties (Feature.reducer, Feature.logic, and Feature.route respectively) ... see: Extendable aspects

  2. all of our app features are supplied (accumulated from the features/ directory)

  3. a registerRootAppElm() callback is used to catalog the supplied rootAppElm to the specific React platform in use. Because this registration is accomplished by your app-specific code, feature-u can operate in any of the React platforms, such as: React Web, React Native, Expo, etc. ... see: React Registration

  4. as a bit of a preview, the return value of launchApp() is an App object, which promotes the accumulated Public API of all features. The App object contains named feature nodes, and is exported to provide Cross Feature Communication ... here is what app looks like (for this example):

    app: {
      featureA: {
        api: {
          open(),
          close(),
        },
      },
      featureB: {
        ...
      },
    }
    

Hopefully this gives you a basic feel of how feature-u operates. The subsequent sections will develop a more thorough understanding!

Real Example

Want to see a real feature-u app?

eatery-nod is the application where feature-u was conceived. It is a react-native expo mobile app, and is one of my sandbox applications that I use to test frameworks. I like to develop apps that I can use, but have enough real-world requirements to make it interesting.

eatery-nod randomly selects a "date night" restaurant from a pool of favorites. My wife and I have a steady "date night", and we are always indecisive on which of our favorite restaurants to frequent :-) So eatery-nod provides the spinning wheel!

results matching ""

    No results matching ""