Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Using Redux with React

Using Redux with React

D9e65f4b0af059ae9ba243c8c2265e4f?s=128

Jussi Pohjolainen

November 07, 2020
Tweet

Transcript

  1. Using Redux with React Jussi Pohjolainen

  2. 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
  3. https://medium.com/better-programming/a-simple-redux- tutorial-starter-complete-code-example-9b2923572d71

  4. 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
  5. 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
  6. 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
  7. Redux has one Global Store import { createStore } from

    'redux'; const store = createStore(); Will fail: Error: Expected the reducer to be a function.
  8. 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
  9. 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
  10. Changing state • Action: object with property 'type' • {type:

    "INCREMENT"}
  11. 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!
  12. 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
  13. 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
  14. 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()));
  15. React + Redux const App = () => ( <Provider

    store={store}> <Counter/> </Provider> ) Every component will have access to store (connect first)
  16. Local State: not using redux function Counter() { let [counter,

    setCounter] = React.useState(0) return <div> <h1>Counter</h1> <button onClick={ () => setCounter(counter + 1) }>+</button> {counter} <button onClick={ () => setCounter(counter - 1) }>-</button> </div> }
  17. Removal of local state and use props function Counter(props) {

    console.log(props) // {} // let [counter, setCounter] = React.useState(0) return <div> <h1>Counter</h1> <button onClick={ () => null }>+</button> {props.count} <button onClick={ () => null }>-</button> </div> } Using props, it's empty
  18. Connecting to redux import { connect } from 'react-redux'; function

    mapStateToProps(state) { return { count: state.count }; } function Counter(props) { console.log(props) // {count: 1} return <div> <h1>Counter</h1> <button onClick={() => null}>+</button> {props.count} <button onClick={() => null}>-</button> </div> } 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!
  19. Dispatch import { connect } from 'react-redux'; function mapStateToProps(state) {

    return { count: state.count }; } function Counter(props) { console.log(props) // {count: 1} return <div> <h1>Counter</h1> <button onClick={() => props.dispatch({ type: "INCREMENT" }) }>+</button> {props.count} <button onClick={() => props.dispatch({ type: "DECREMENT" }) }>-</button> </div> } 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!
  20. Communication using Redux

  21. Two Siblings function App() { return ( <div> <IncrementDecrement />

    <DisplayCount /> </div> ); }
  22. Providing Store import store from "./Store.js"; import { Provider }

    from "react-redux"; ReactDOM.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode>, document.getElementById("root") );
  23. 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;
  24. IncrementDecrement import { connect } from "react-redux"; function IncrementDecrement(props) {

    const add = () => { props.dispatch({ type: "INCREMENT" }); }; const remove = () => { props.dispatch({ type: "DECREMENT" }); }; return ( <div> <button onClick={add}>+</button> <button onClick={remove}>-</button> </div> ); } export default connect()(IncrementDecrement);
  25. DisplayCount import { connect } from "react-redux"; function mapStateToProps(state) {

    return { id: state.count, }; } function DisplayCount(props) { return <div>count = {props.id}</div>; } export default connect(mapStateToProps)(DisplayCount);