Slide 1

Slide 1 text

Using Redux with React Jussi Pohjolainen

Slide 2

Slide 2 text

Redux: Motivation • Avoid prop-drilling, passing props between components can be a pain, if several components • A -> B -> C -> D • B and C only are here passing data, they do not do anything to it, only D wants the data. • Passing data between siblings is a pain also • Pull data up into parent component and pass it down with props

Slide 3

Slide 3 text

https://medium.com/better-programming/a-simple-redux- tutorial-starter-complete-code-example-9b2923572d71

Slide 4

Slide 4 text

Redux to rescue • Redux gives you one global "parent" where you store your data • Connect sibling components to the data with Redux • On source of "truth", components can ask data from the redux store

Slide 5

Slide 5 text

Redux alternative • Redux uses Context API to pass data around • It is possible to use Context API directly but you will miss out some of Redux nice features • If your app is really simple and you want to pass data around, Context API might be good for you • useContext, useReducer hooks

Slide 6

Slide 6 text

Install • Redux: • Gives you store, lets you keep state in it, get state out and respond to state changes. Knows nothing about React! • React redux • Connect pieces of the state to react components • To install • npm install redux react-redux

Slide 7

Slide 7 text

Redux has one Global Store import { createStore } from 'redux'; const store = createStore(); Will fail: Error: Expected the reducer to be a function.

Slide 8

Slide 8 text

Using reducer import { createStore } from 'redux'; function reducer(state, action) { console.log('reducer', state, action); return state; } const store = createStore(reducer); current state and an action. Returns new state

Slide 9

Slide 9 text

Initial state import { createStore } from 'redux'; function reducer(state = { count: 0 }, action) { console.log('reducer', state, action); return state; } const store = createStore(reducer); Setting initial state

Slide 10

Slide 10 text

Changing state • Action: object with property 'type' • {type: "INCREMENT"}

Slide 11

Slide 11 text

Example import { createStore } from 'redux'; function reducer(state = { count: 0 }, action) { console.log('reducer', state, action); return state; } const store = createStore(reducer); store.dispatch({ type: "INCREMENT" }); Dispatching action!

Slide 12

Slide 12 text

import { createStore } from 'redux'; function reducer(state = { count: 0 }, action) { console.log('reducer', state, action); switch(action.type) { case 'INCREMENT': return { count: state.count + 1 }; case 'DECREMENT': return { count: state.count - 1 }; default: return state; } } const store = createStore(reducer); store.dispatch({ type: "INCREMENT" }); store.dispatch({ type: "DECREMENT" }); store.dispatch({ type: "INCREMENT" }); Act on actions state is read only, do NOT modify return new state

Slide 13

Slide 13 text

import { createStore } from 'redux'; function reducer(state = { count: 0 }, action) { console.log('reducer', state, action); switch(action.type) { case 'INCREMENT': return { count: state.count + 1 }; case 'DECREMENT': return { count: state.count - 1 }; default: return state; } } const store = createStore(reducer); store.dispatch({ type: "INCREMENT" }); store.dispatch({ type: "DECREMENT" }); store.dispatch({ type: "INCREMENT" }); Act on actions state is read only, do NOT modify return new state

Slide 14

Slide 14 text

Subscribing to Store let { createStore } = require("redux"); function reducer(state = { count: 0 }, action) { switch (action.type) { case "INCREMENT": return { count: state.count + 1 }; case "DECREMENT": return { count: state.count - 1 }; default: return state; } } const store = createStore(reducer); store.subscribe(() => console.log(store.getState()));

Slide 15

Slide 15 text

React + Redux const App = () => ( ) Every component will have access to store (connect first)

Slide 16

Slide 16 text

Local State: not using redux function Counter() { let [counter, setCounter] = React.useState(0) return

Counter

setCounter(counter + 1) }>+ {counter} setCounter(counter - 1) }>-
}

Slide 17

Slide 17 text

Removal of local state and use props function Counter(props) { console.log(props) // {} // let [counter, setCounter] = React.useState(0) return

Counter

null }>+ {props.count} null }>-
} Using props, it's empty

Slide 18

Slide 18 text

Connecting to redux import { connect } from 'react-redux'; function mapStateToProps(state) { return { count: state.count }; } function Counter(props) { console.log(props) // {count: 1} return

Counter

null}>+ {props.count} null}>-
} export default connect(mapStateToProps)(Counter) Returning connected component! Uses a custom function to map universal state to props Function that gets the universal state and transforms it to props Props is now available!

Slide 19

Slide 19 text

Dispatch import { connect } from 'react-redux'; function mapStateToProps(state) { return { count: state.count }; } function Counter(props) { console.log(props) // {count: 1} return

Counter

props.dispatch({ type: "INCREMENT" }) }>+ {props.count} props.dispatch({ type: "DECREMENT" }) }>-
} export default connect(mapStateToProps)(Counter) https://daveceddia.com/redux-tutorial/ https://www.valentinog.com/blog/redux/#react-redux-tutorial-getting-to-know-redux-reducers Props is filled also with dispatch function!

Slide 20

Slide 20 text

Communication using Redux

Slide 21

Slide 21 text

Two Siblings function App() { return (
); }

Slide 22

Slide 22 text

Providing Store import store from "./Store.js"; import { Provider } from "react-redux"; ReactDOM.render( , document.getElementById("root") );

Slide 23

Slide 23 text

Store import { createStore } from "redux"; function reducer(state = { count: 0 }, action) { switch (action.type) { case "INCREMENT": return { count: state.count + 1 }; case "DECREMENT": return { count: state.count - 1 }; default: return state; } } const store = createStore(reducer); export default store;

Slide 24

Slide 24 text

IncrementDecrement import { connect } from "react-redux"; function IncrementDecrement(props) { const add = () => { props.dispatch({ type: "INCREMENT" }); }; const remove = () => { props.dispatch({ type: "DECREMENT" }); }; return (
+ -
); } export default connect()(IncrementDecrement);

Slide 25

Slide 25 text

DisplayCount import { connect } from "react-redux"; function mapStateToProps(state) { return { id: state.count, }; } function DisplayCount(props) { return
count = {props.id}
; } export default connect(mapStateToProps)(DisplayCount);