If like me, you felt a bit overwhelmed by all the possibilities offered in the basic tutorial of React-redux.js, this article is for you.
I going to code a simple add-to-a-list app. Type a new element in an input and add it to the list that is rendered below. Very simple.
This post assumes you know the basics of Javascript and React. And of course, React, Redux and React-redux modules need to be installed for such a project to work.
The main idea is to have a single state for the whole app.
-
The state is in the Redux store.
-
To add to the state one must go through two steps (a safety measure).
- Step one: describe the action in an object, the action creator.
- Step two: given the action, the reducer will update the state. It’s just a function that takes state and action as arguments, and returns the next state of the app.
-
React-redux is here to help pass the state to the component.
Refer to the Three Principles.
- store : where the state is stored as a object tree.
- action : an object describing the change to the state.
- reducer : a function that returns the new state.
- Provider : takes the store as props and makes it available to the nested components.
- connect : a function that connects a React component to the Redux store.
- Point of entry : The
App
component that holds theProvider
. like so :
const store = createStore(reducer, ['Use Redux']);
function App() {
return (
<Provider store={store}>
<ToAdd />
<Display />
{console.log(store.getState())}
</Provider>
);
The store is created, with the reducer function as argument which will return the next state given the action. Here I have added a initial entry in the list ('Use Redux') to show that the state from the store was rendered.
- The
reducer
, as stated before is a simple function that takes the state and the action as arguments. In this example, there is only one action, add to the list. Here our action object has two keys. See next point for further details.
function reducer(state = [], action) {
switch (action.type) {
case "ADD_TODO":
return state.concat([action.content]);
default:
return state;
}
}
- The
action
is the object with the description of the action (type) and the element of change (content).
const addTodo = content => ({
type: "ADD_TODO",
content
});
- Now for the presentational components, let's first have a look at
ToAdd
, and how to add content to the state.
class ToAdd extends React.Component {
constructor(props) {
super(props);
this.state = {
inputStr: ""
};
}
updateInput = input => {
this.setState({ inputStr: input });
};
handleAddTodo = () => {
this.props.addTodo(this.state.inputStr);
this.setState({ inputStr: "" });
};
render() {
return (
<div>
<input
onChange={e => this.updateInput(e.target.value)}
value={this.state.inputStr}
/>
<button onClick={this.handleAddTodo}>add</button>
</div>
);
}
}
export default connect(
null ,
{ addTodo }
)(ToAdd);
We have an input for the user to type in, this value is saved in a state belonging to the ToAdd component. On submit, the value is passed to the action creator. To dispatch the action, we use the connect function. As React-redux recommends, I am using the “object shorthand” form. Note: the null argument is to not subscribe to the store. Indeed we are not rendering just yet.
- Lastly the
Display
component. This time we will subscribe to the store to render any changes.
const Display = (stuff) => {
return(
<div>
<ol>
{stuff.state.map((e,id)=>
(<li key={id}>{e}</li>)
)}
</ol>
{console.log(stuff)}
</div>
);
};
const mapStateToProps = state => {
return {state};
};
export default connect(mapStateToProps)(Display);
We just need to define a special function called mapStateToProps that access the current Redux store state tree. We pass it into the props to the component and well the rest is quite self-explanatory.
That was quite simple, wasn't it ?
From here, it should be easier to understand the use of selectors, multiple reducers and the combineReducers function and more.
I hope this article was helpful to some.
Happy coding !