- Notifications
You must be signed in to change notification settings - Fork1
Microframework for structuring code of React/Redux applications
License
FactorialComplexity/react-redux-controllers
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
NOTE: This guide assumes the reader is familiar withRedux andReact.
This microframework was created for organizing the code of React/Redux applications. It is important to understand that itdoes not introduce any new fundamental concepts to how regular React/Redux applicationworks. The goal is to provide the utilities for structuring React/Redux code in a way, that makes it more readable, manageable and reusable.
This is achieved by two essential primitives:
And one small, but important utility class:
NOTE:Action in fact can be used in any Redux application separately from the rest of the framework. Action class itself has zero dependencies.
The library is available as a package on NPM:
npm install --save react-redux-controllersIn order to make it work you need to replace Redux versions ofcreateStore() andcombineReducers() with ones provided by current package. I.e. basically replace :
import{createStore,combineReducers}from'redux'
With:
import{createStore,combineReducers}from'react-redux-controllers'
NOTE: If you use require() modify the code above accordingly.
Any regular Redux code will continue to work. These functions call their vanilla Redux counterparts under the hood. They do exactly the same, unless you start passing Controller instances into combineReducers() additionally to regular reducers.
As the name of the library implies, the central concept isController. However, this isnot a controller as in MVC. It is better to think of it as a "data controller", responsible for managing the certain part of the applicationstate. This includes:
- Sending relevantactions in response to certain related events.
- Modifying the state by providing the relevantreducer.
- Providing access and if necessarytransforming the data in the managed part of thestate.
Developers utilize controllers by subclassing theController class provided by the framework. Instances of the Controller subclasses should then be mounted into the Redux store. This is done by passing them tocombineReducers() in place of regular reducer functions.
const reducer = combineReducers({ todo: new ToDoController()})Controllers encapsulate all the data processing logic, but it is up toContainers to connect it to the view layer. This is what youconnect() for in traditional Redux application. And in factContainer() calls it under the hood. However, instead of requiring to write the boringmapToState andmapToDispatch stuff, we will just connect it to the Controller referenced by path where it was mounted.
import{Container}from'react-redux-controllers'classToDoextendsComponent{// ...}exportdefaultContainer(ToDo,"todo.*");
Behind the scene this automatically maps the whole portion of state tree atstate.todo to the props of the exported component. However, there are couple of twists that make this more fun:
- Any method in Controller which starts with
$is considered to be a "selector". It is called whenever the relevant part of the state needs to be mapped: either by Container or withController.$() function. - Keys in the state that go immediately below the Controller's level can be marked "private" by prepending them with underscore (
_). These keys are explicitly ignored by both Container andController.$() function. - Any method in Controller which start with
dispatchis considered to be a "dispatch" method. It can be automatically mapped to the props by Container.
Containers allow a lot of options for controlling what is mapped where. The details can be found inAPI documentation. Good practive however is to place all of the selector logic into Controller with minimal remapping in Containers.
Here is a quick example of the simple controller to show framework in action.
import{Controller}from'react-redux-controllers'classToDoControllerextendsController{constructor(){super()// Create new Action and save it into this.actions.addthis.createAction('add')}// Provides reducer to be used by storereducer(){const{ add}=this.actions// this.createReducer is just a shortcut to Action.createReducer,// so you do not have to import Actionreturnthis.createReducer(add.on((state,text)=>({_items:(state._items||[]).concat({ text})})))}// Dispatch function. Will be mapped as `add(text)` in ContainerdispatchAdd(text){this.dispatchAction('add',text)}// Selector function. Will be used to collect data for `props.text` in Container$texts(state){return(this.$$(state)._items||[]).map((item)=>item.text)}}
The component that works with the controller can look this way:
import{Container}from'react-redux-controllers'classToDoextendsComponent{render(){const{ texts, add}=this.propsreturn(<ul>{texts.map((text,i)=>(<likey={i}>{text}</li>))}</ul><buttononclick={add("Do something!")}>Add</button>)}}exportdefaultContainer(ToDo,"todo.*");
About
Microframework for structuring code of React/Redux applications
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.