Skip to content

neurosnap/redux-plugin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Redux Plugin

Organize code by feature without worrying about circular dependencies.

Redux plugin is a dependency injector that creates clear boundaries between plugins.

If a module depends on another module but that module has been removed, the module will continue to work properly while displaying a warning that there are missing pieces.

moduleA.js

const reducers = {
  counter: (state, action, actionTypes) => {
  case actionTypes.ADD:
    return state + 1;

  case actionTypes.ADD_FAILURE:
    return state - 1;

  default:
    return state;
  }
};

const selectors = {
  getCount: (state) => state.counter,
};

export default {
  reducers,
  selectors,
};

moduleB.js

import { take, call, put } from 'redux-saga';

const actionTypes = {
  ADD: 'todo/ADD',
  ADD_SUCCESS: 'todo/ADD_SUCCESS',
  ADD_FAILURE: 'todo/ADD_FAILURE',
};

const actionCreators = {
  add: (payload) => ({
    type: actionTypes.ADD,
    payload,
  }),
  addSuccess: () => ({ type: actionTypes.ADD_SUCCESS }),
  addFailure: () => ({ type: actionTypes.ADD_FAILURE }),
};

const reducers = {
  todos: (state, action, actionTypes) => {
  case actionTypes.ADD:
    return [...state, action.payload];

  default:
    return state
  }
};

const sagas = {
  addTodoSaga: function* (modules) {
    const { ADD } = modules.actionTypes;
    const { addSuccess, addFailure } = modules.actionCreators;

    while (true) {
      const action = yield take(ADD);
      const text = action.payload;

      const response = yield call(fetch, {
        url: '/todo/add',
        method: 'POST',
        body: JSON.stringify({ text }),
      });

      if (response.status >= 200 && response.status < 300) {
        yield put(addSuccess());
      } else {
        yield put(addFailure());
      }
    }
  }
};

const selectors = {
  getTodos: (state) => state.todos,
};

export default {
  actionTypes,
  actionCreators,
  reducers,
  sagas,
  selectors,
};

app.js

import { connect } from 'redux-plugin';

const App = ({ count, add }) => (
  <div>
    {todos.map((todo) => <div>{todo}</div>)}
    <button onClick={() => add('THIS IS A TODO')}>Add TODO</button>
    <div>Number of TODOs: {count}</div>
  </div>
);

const mapStateToProps = (state, { selectors }) => ({
  count: selectors.getCount(state),
  todos: selectors.getTodos(state),
});

const mapDispatchToProps = (dispatch, { actionCreators }) => ({
  add: (text) => dispatch(actionCreators.add(text)),
});

export default connect(mapStateToProps, mapDispatchToProps)(App);

index.js

import { createStore, compose, applyMiddleware, combineReducers } from 'redux';
import { sagaMiddleware } from 'redux-saga';
import { Provider } from 'react-redux';
import { use, Provider as PluginProvider, sagaCreator } from 'redux-plugin';

import App from './app';
import moduleA from './moduleA';
import moduleB from './moduleB';

const enhancer = compose(applyMiddleware(sagaMiddleware));
// initialize modules
const modules = use([moduleA, moduleB]);

// create root reducer
const reducer = combineReducers(modules.reducers);

// initialize store
const store = createStore(reducer, {}, enhancer);

// create root saga
const saga = sagaCreator(modules);

// initialize sagas
sagaMiddleware.run(saga);

// render app with providers
reactDOM.render(
  <Provider store={store}>
    <PluginProvider modules={modules}>
      <App />
    </PluginProvider>
  </Provider>,
  document.getElementById('app')
);

About

Something something plugins for react redux

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published