Wondering what’s next for npm?Check out our public roadmap! »

    weeflux

    1.0.4 • Public • Published

    Weeflux

    A state management based on flux architecture
    Weeflux in actions

    import React from 'react';
    import { render } from 'react-dom';
    import flux, { clean, middleware, subscribe, hoc } from './weeflux';
    import partial from './weeflux-partial-reducer';
    import uuid from 'uuid';
    import produce from 'immer';
     
    clean();
     
    // define some actions
    const actions = {
      add: 'add',
      remove: 'remove',
      textChanged: 'text-changed',
      rollback: 'rollback',
      profileLoaded: 'loaded',
      profileFailed: 'failed',
      profileLoading: 'loading'
    };
     
    // inject immer for state updating
    const immerMiddleware = next => context => {
      return produce(context.getState(), draft =>
        next({
          ...context,
          getState() {
            return draft;
          }
        })
      );
    };
     
    // logging middleware
    const logMiddleware = next => context => {
      const before = context.getState();
      console.log('before', context.action, before);
      const after = next(context);
      console.log('after', context.action, after);
      return after;
    };
     
    const history = [];
    const timemachineMiddleware = next => context => {
      if (context.action === actions.rollback) {
        const historyIndex = context.payload;
        // clean history
        history.splice(historyIndex + 1, history.length);
     
        return next({
          ...context,
          payload: undefined,
          getState() {
            return history[historyIndex] || {};
          }
        });
      }
      const before = context.getState();
      if (before !== history[history.length - 1]) {
        history.push(before);
      }
     
      return next(context);
    };
     
    const asyncMiddleware = next => context => {
      // is promise
      if (context.payload && context.payload.then) {
        const { defaultValue, success, failure } = context.extra[0] || {};
        context.payload.then(
          response => flux(success, { status: 'success', response }),
          error => flux(failure, { status: 'failure', error })
        );
     
        return next({
          ...context,
          payload: {
            status: 'start',
            response: defaultValue
          }
        });
      }
      return next(context);
    };
     
    // install middlewares
     
    middleware(immerMiddleware);
    middleware(asyncMiddleware);
    middleware(logMiddleware);
    middleware(timemachineMiddleware);
     
    // init state
    flux({
      todos: {},
      ids: [],
      text: ''
    });
     
    // subscription
    subscribe(console.log, 'state-changed');
     
    // reducer for todo actions
    flux((state, { action, payload }) => {
      switch (action) {
        case actions.add:
          const id = uuid();
          state.todos[id] = { text: payload };
          state.ids.push(id);
          break;
        case actions.remove:
          delete state.todos[payload];
          state.ids.splice(state.ids.indexOf(payload), 1);
          break;
      }
    });
     
    // dispatch some actions
    flux(actions.add, 'Task 1');
    flux(actions.add, 'Task 2');
    flux(actions.add, 'Task 3');
     
    // register hoc, this hoc will be activated if component options contains stateToProps prop
    hoc('stateToProps', stateToProps => Component => {
      return class WrappedComponent extends React.Component {
        componentDidMount() {
          // subscribe method returns a function which can be use to unsubscribe subscription later
          this.unsubscribe = subscribe(() => !this.unmount && this.forceUpdate());
        }
     
        componentWillUnmount() {
          this.unmount = true;
          this.unsubscribe();
        }
        render() {
          // map state to props
          const props = stateToProps(flux(), this.props);
          return <Component {...props} />;
        }
      };
    });
     
    // reducer for text
    flux(partial('text', actions.textChanged, (state, { payload }) => payload));
     
    flux(
      partial(
        'profile',
        // handle multiple actions with one reducer
        [actions.profileLoaded, actions.profileFailed, actions.profileLoading],
        (state, { payload }) => payload
      )
    );
     
    const fetchData = url =>
      new Promise((resolve, reject) => {
        setTimeout(
          () =>
            fetch(url)
              .then(res => res.text())
              .then(resolve, reject),
          3000
        );
      });
     
    flux(
      actions.profileLoading,
      fetchData('https://api.github.com/users/linq2js'),
      {
        defaultValue: { thisIsFirstProfile: true },
        failure: actions.profileFailed,
        success: actions.profileLoaded
      }
    );
     
    const stateToProps = state => ({ text: state.text });
     
    const Input = flux({ stateToProps }, props => (
      <input
        type="text"
        value={props.text}
        onChange={e => flux(actions.textChanged, e.target.value)}
      />
    ));
     
    const Output = flux({ stateToProps }, props => <div>{props.text}</div>);
     
    const History = flux({ stateToProps: () => ({ history }) }, props => (
      <div>
        <strong>History</strong>
        <ol>
          {props.history.map((item, index) => (
            // display history item
            <li key={index} onClick={() => flux(actions.rollback, index)}>
              {JSON.stringify(item)}
            </li>
          ))}
        </ol>
      </div>
    ));
     
    const App = () => (
      <div>
        <Input />
        <Output />
        <History />
      </div>
    );
     
    render(<App />, document.getElementById('root'));

    Install

    npm i weeflux

    DownloadsWeekly Downloads

    3

    Version

    1.0.4

    License

    MIT

    Unpacked Size

    37.1 kB

    Total Files

    13

    Last publish

    Collaborators

    • avatar