This week I thought I'd talk about learning Redux. At first, Redux can feel like difficult transition for someone who is used React. But the more I learn, the less daunting it seems and I might got so far as to say that I'm actually getting really excited about Redux.
Now I'm still really new to Redux so in this blog I'll just be sharing what I've learned so far, which is a big picture view of the data flow in Redux.
If you're familiar with React you'll know that data in that framework is stored in state and passed down to a child component as props. If your app has a big component tree, this can turn into a complex web of state and props. In Redux there is a state object that is separate from all the components and that is accessible to any component that needs it. So if React is providing traditional cable TV service, Redux is providing satellite!
Actions
Let's break down how this works and then we'll put it all together. If we want to alter state in Redux, first we need to create an action. Actions are just objects that tell Redux how to update state.
const action = { type: 'MULTIPLY_BY_2' }
Reducers
Then we need to pass that to a function that will use that action and the current state to make a change to state. In Redux, these functions are called reducers. Reducers use a switch statement to carry out an update of state by on the action's type. Notice that the switch statement has a default. This ensures that we always have a valid state object.
let state = { number: 1 };
function reducer(state, action) {
switch(action.type) {
case 'MULTIPLY_BY_2':
return {number: state.number * 2};
default:
return state
}
}
console.log(reducer(state, { type: 'MULTIPLY_BY_2' }));
console.log(reducer(state, { type: 'MULTIPLY_BY_2' }));
console.log(reducer(state, { type: 'MULTIPLY_BY_2' }));
If you run this code, you'll get:
{ number: 2 }
{ number: 2 }
{ number: 2 }
Well that's not exactly what we want. If was call the reducer 3 times, what we really want is state to update to 2,4 and then 8. It's not doing this because reducer just returns a new object with the updated value rather than updating state. We need to update state to make the change persistent.
Dispatch Functions
This is where the dispatch function comes in. Dispatch sends the current state and the action to the reducer and then uses the return value to update state. It looks like this:
let state = { number: 1 };
function reducer(state, action) {
switch(action.type) {
case 'MULTIPLY_BY_2':
return {number: state.number * 2};
default:
return state
}
}
function dispatch(action) {
return state = reducer(state, action);
}
console.log(dispatch({ type: 'MULTIPLY_BY_2' }));
console.log(dispatch({ type: 'MULTIPLY_BY_2' }));
console.log(dispatch({ type: 'MULTIPLY_BY_2' }));
Now we get:
{ number: 2 }
{ number: 4 }
{ number: 8 }
Awesome! Our state is updating with each call to dispatch. The next step is to make sure that those changes are rendered on the DOM. This can be accomplished with a render function and a refactor of the dispatch function. Since we don't have one, I'll be referencing elements in a hypothetical index.html file.
function dispatch(action) {
state = reducer(state, action);
render();
}
function render() {
let container = document.getElementById('container');
container.textContent = state.count;
}
Now every time dispatch is called, the DOM will be updated with the newest version of state.
Interactions
Last piece of the Redux data flow is setting up when dispatch is called. To do this we're gonna use a vanilla JavaScript event listener. Again we'll reference elements in a hypothetical index.html file. With this final addition, our total block of code will look like this:
let state = { number: 1 };
function reducer(state, action) {
switch(action.type) {
case 'MULTIPLY_BY_2':
return {number: state.number * 2};
default:
return state
}
}
function dispatch(action) {
state = reducer(state, action);
render();
}
function render() {
let container = document.getElementById('container');
container.textContent = state.count;
}
let button = document.getElementById('button');
button.addEventListener('click', () => {
dispatch({type: 'MULTIPLY_BY_2'})
})
Now anytime the "multiply by 2" button is pressed, dispatch({type: 'MULTIPLY_BY_2'}) will be called and the data flow will begin.
Conclusion
To put this all together look at the data flow for a birds eye view.
Big picture we see that data flow in Redux follows these steps:
- An interaction happens (mouse click, form submit, etc.)
- The interaction creates an Action, which is basically an instruction on how State should be updated.
- The Action is sent to the Dispatch function, which passes the action and the current State to the Reducer function.
- The Reducer function uses the Action to modify a copy of State and then returns that updated copy to the Dispatch Function.
- The Dispatch function then sets State to be equal to the object returned from the Reducer function.
- Finally, the fact that State was updated causes the view to re-render and the cycle is complete.
Song of the Week:
Nakama's Dance - Ariel T | Spotify
References
I have been learning Redux from my Flatiron School lessons, which are not available to the general public. But click the link below to be taken to the Redux website where they have information to get you started.
Top comments (0)