The State of React State in 2019

A presentation at React Conf in October 2019 in Henderson, NV, USA by Becca Bailey

Slide 1

Slide 1

The State of React State in 2019 Becca Bailey • React Conf 2019 @beccaliz

Slide 2

Slide 2

Hi, I’m Becca! Chicago, IL @beccaliz

Slide 3

Slide 3

Slide 4

Slide 4

Slide 5

Slide 5

Slide 6

Slide 6

Slide 7

Slide 7

Slide 8

Slide 8

Slide 9

Slide 9

Why this talk?

Slide 10

Slide 10

The Newbie @beccaliz

Slide 11

Slide 11

@beccaliz

Slide 12

Slide 12

@beccaliz

Slide 13

Slide 13

@beccaliz

Slide 14

Slide 14

@beccaliz

Slide 15

Slide 15

❔ ❔ @beccaliz ❔

Slide 16

Slide 16

The Loyalist @beccaliz

Slide 17

Slide 17

“If it ain’t broke, don’t fix it!” @beccaliz

Slide 18

Slide 18

@beccaliz

Slide 19

Slide 19

@beccaliz

Slide 20

Slide 20

redux react @beccaliz

Slide 21

Slide 21

redux react @beccaliz

Slide 22

Slide 22

redux react @beccaliz MobX

Slide 23

Slide 23

apollo redux react @beccaliz MobX

Slide 24

Slide 24

context apollo redux react @beccaliz MobX

Slide 25

Slide 25

context apollo redux react @beccaliz hooks MobX

Slide 26

Slide 26

context apollo redux react @beccaliz hooks MobX

Slide 27

Slide 27

@beccaliz

Slide 28

Slide 28

The Explorer @beccaliz

Slide 29

Slide 29

@beccaliz

Slide 30

Slide 30

@beccaliz

Slide 31

Slide 31

@beccaliz

Slide 32

Slide 32

@beccaliz

Slide 33

Slide 33

@beccaliz

Slide 34

Slide 34

@beccaliz

Slide 35

Slide 35

@beccaliz

Slide 36

Slide 36

❔ @beccaliz

Slide 37

Slide 37

❔ @beccaliz ❔

Slide 38

Slide 38

❔ ❔ @beccaliz ❔

Slide 39

Slide 39

@beccaliz

Slide 40

Slide 40

Slide 41

Slide 41

@beccaliz

Slide 42

Slide 42

@beccaliz

Slide 43

Slide 43

@beccaliz

Slide 44

Slide 44

@beccaliz

Slide 45

Slide 45

@beccaliz

Slide 46

Slide 46

@beccaliz

Slide 47

Slide 47

@beccaliz

Slide 48

Slide 48

  1. Clarify @beccaliz the problem

Slide 49

Slide 49

  1. Clarify the problem 2. Explore some solutions @beccaliz

Slide 50

Slide 50

  1. Clarify the problem 2. Explore some solutions 3. Make decisions @beccaliz

Slide 51

Slide 51

Slide 52

Slide 52

State @beccaliz

Slide 53

Slide 53

@beccaliz

Slide 54

Slide 54

setState @beccaliz

Slide 55

Slide 55

setState @beccaliz useState

Slide 56

Slide 56

Local State @beccaliz

Slide 57

Slide 57

@beccaliz

Slide 58

Slide 58

You win! Yay! @beccaliz

Slide 59

Slide 59

1 class MyComponent extends React.Component { 2 state = { 3 visible: false 4 }; 5 6 showModal() { 7 this.setState(state => ({ 8 visible: true 9 })); 10 } 11 12 hideModal() { 13 this.setState(state => ({ 14 visible: false 15 })); 16 } 17 18 render() { 19 …stuff here 20 } 21 }

Slide 60

Slide 60

1 class MyComponent extends React.Component { 2 state = { 3 visible: false 4 }; 5 6 showModal() { 7 this.setState(state => ({ 8 visible: true 9 })); 10 } 11 12 hideModal() { 13 this.setState(state => ({ 14 visible: false 15 })); 16 } 17 18 render() { 19 …stuff here 20 } 21 }

Slide 61

Slide 61

1 class MyComponent extends React.Component { 2 state = { 3 visible: false 4 }; 5 6 showModal() { 7 this.setState(state => ({ 8 visible: true 9 })); 10 } 11 12 hideModal() { 13 this.setState(state => ({ 14 visible: false 15 })); 16 } 17 18 render() { 19 …stuff here 20 } 21 }

Slide 62

Slide 62

1 const MyComponent = () => { 2 const [visible, setVisible] = React.useState(false); 3 4 function showModal() { 5 setVisible(true); 6 } 7 8 function hideModal() { 9 setVisible(false); 10 } 11 12 return ( 13 …stuff here 14 ); 15 };

Slide 63

Slide 63

1 const MyComponent = () => { 2 const [visible, setVisible] = React.useState(false); 3 4 function showModal() { 5 setVisible(true); 6 } 7 8 function hideModal() { 9 setVisible(false); 10 } 11 12 return ( 13 …stuff here 14 ); 15 };

Slide 64

Slide 64

1 const MyComponent = () => { 2 const [visible, setVisible] = React.useState(false); 3 4 function showModal() { 5 setVisible(true); 6 } 7 8 function hideModal() { 9 setVisible(false); 10 } 11 12 return ( 13 …stuff here 14 ); 15 };

Slide 65

Slide 65

Prop Drilling @beccaliz

Slide 66

Slide 66

1 // App.js 2 const App = () => { 3 4 return ( 5 <Container> 6 <Game></Game> 7 </Container> 8 ); 9 };

Slide 67

Slide 67

const user = { id: 123, firstName: “Becca”, lastName: “Bailey”, email: “beccanelsonbailey@gmail.com”, marker: ” ” }

Slide 68

Slide 68

1 // App.js 2 const App = () => { 3 const [user, updateUser] = React.useState(); 4 5 React.useEffect(async () => { 6 const user = await fetchLoggedInUser(); 7 updateUser(user); 8 }, []) 9 10 return ( 11 <Container> 12 <Game user={user}></Game> 13 </Container> 14 ); 15 };

Slide 69

Slide 69

1 // Game.js 2 const Game = ({ user }) => { 3 const [board, updateBoard] = React.useState(EMPTY_BOARD 4 5 function makeMove(index) { 6 updateBoard({…board, [index]: user.marker }) 7 } 8 9 return ( 10 <React.Fragment> 11 <h1>Hello {user.name}!</h1> 12 <Board board={board} makeMove={makeMove} /> 13 </React.Fragment> 14 ); 15 };

Slide 70

Slide 70

1 // Game.js 2 const Game = ({ user }) => { 3 const [board, updateBoard] = React.useState(EMPTY_BOARD 4 5 function makeMove(index) { 6 updateBoard({…board, [index]: user.marker }) 7 } 8 9 return ( 10 <React.Fragment> 11 <Greeting user={user} /> 12 <Board board={board} makeMove={makeMove} /> 13 </React.Fragment> 14 ); 15 };

Slide 71

Slide 71

Repetition @beccaliz

Slide 72

Slide 72

Slide 73

Slide 73

You win! Yay!

Slide 74

Slide 74

Slide 75

Slide 75

⚠ Error! Oh no!

Slide 76

Slide 76

showModal modalOpen modalIsVisible modalIsOpen modalVisible @beccaliz

Slide 77

Slide 77

@beccaliz

Slide 78

Slide 78

@beccaliz

Slide 79

Slide 79

You win! Yay! @beccaliz

Slide 80

Slide 80

You win! ⚠ Error! Yay! Oh no! @beccaliz

Slide 81

Slide 81

@beccaliz

Slide 82

Slide 82

@beccaliz

Slide 83

Slide 83

@beccaliz

Slide 84

Slide 84

@beccaliz

Slide 85

Slide 85

} @beccaliz local state

Slide 86

Slide 86

Global state @beccaliz

Slide 87

Slide 87

@beccaliz

Slide 88

Slide 88

@beccaliz

Slide 89

Slide 89

@beccaliz

Slide 90

Slide 90

@beccaliz

Slide 91

Slide 91

} global state @beccaliz

Slide 92

Slide 92

@beccaliz

Slide 93

Slide 93

@beccaliz

Slide 94

Slide 94

@beccaliz

Slide 95

Slide 95

@beccaliz

Slide 96

Slide 96

} semi­local state @beccaliz

Slide 97

Slide 97

Flux Architecture @beccaliz

Slide 98

Slide 98

@beccaliz

Slide 99

Slide 99

action @beccaliz

Slide 100

Slide 100

action @beccaliz

Slide 101

Slide 101

reducer action @beccaliz

Slide 102

Slide 102

reducer action @beccaliz

Slide 103

Slide 103

reducer action @beccaliz store

Slide 104

Slide 104

reducer action @beccaliz store

Slide 105

Slide 105

reducer store action view @beccaliz

Slide 106

Slide 106

reducer store action view @beccaliz

Slide 107

Slide 107

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // actions.js export function makeMove(index) { return { type: “MAKE_MOVE”, payload: { index } }; } // reducers.js const game = (state = getInitialState(), action) => { switch (action.type) { case “MAKE_MOVE”: { const { index } = action.payload; return { …state, board: { …state.board, [index]: state.currentPlayer.marker, } }; } default: return state; }

Slide 108

Slide 108

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // actions.js export function makeMove(index) { return { type: “MAKE_MOVE”, payload: { index } }; } // reducers.js const game = (state = getInitialState(), action) => { switch (action.type) { case “MAKE_MOVE”: { const { index } = action.payload; return { …state, board: { …state.board, [index]: state.currentPlayer.marker, } }; } default: return state; }

Slide 109

Slide 109

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Game.js function mapStateToProps({ board }) { return board; } function mapDispatchToProps(dispatch) { return { makeMove: (index) => { dispatch(makeMove(index)); } }; } export default connect( mapStateToProps, mapDispatchToProps )(Game);

Slide 110

Slide 110

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Game.js function mapStateToProps({ board }) { return board; } function mapDispatchToProps(dispatch) { return { makeMove: (index) => { dispatch(makeMove(index)); } }; } export default connect( mapStateToProps, mapDispatchToProps )(Game);

Slide 111

Slide 111

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Game.js function mapStateToProps({ board }) { return board; } function mapDispatchToProps(dispatch) { return { makeMove: (index) => { dispatch(makeMove(index)); } }; } export default connect( mapStateToProps, mapDispatchToProps )(Game);

Slide 112

Slide 112

@beccaliz

Slide 113

Slide 113

Becca played at spot 0 @beccaliz

Slide 114

Slide 114

Becca played at spot 0 Computer played at spot 4 @beccaliz

Slide 115

Slide 115

Becca played at spot 0 Computer played at spot 4 Becca played at spot 7 @beccaliz

Slide 116

Slide 116

Becca played at spot 0 Computer played at spot 4 Becca played at spot 7 Computer played at spot 3 @beccaliz

Slide 117

Slide 117

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // actions.js export function makeMove(index) { return { type: “MAKE_MOVE”, payload: { index } }; } // reducers.js const game = (state = getInitialState(), action) => { switch (action.type) { case “MAKE_MOVE”: { const { index } = action.payload; return { …state, board: { …state.board, [index]: state.currentPlayer.marker, } }; } default: return state; }

Slide 118

Slide 118

@beccaliz

Slide 119

Slide 119

connected store dispatch view @beccaliz props

Slide 120

Slide 120

connected presentational store parent dispatch view @beccaliz props props view

Slide 121

Slide 121

Separation of Concerns @beccaliz

Slide 122

Slide 122

Too much abstraction @beccaliz

Slide 123

Slide 123

@beccaliz

Slide 124

Slide 124

// Board.test.tsx it(“handles click events”, () => { const props = { makeMove: jest.fn(), board: DEFAULT_BOARD }; const { queryAllByRole } = render(<Board {…props}></Board>); fireEvent.click(queryAllByRole(“button”)[0]); expect(props.makeMove).toHaveBeenCalledWith(0); });

Slide 125

Slide 125

// reducers.test.js it(“updates the board state”, () => { expect( reducer(initialState, { type: “MAKE_MOVE”, payload: { index: 2 } }) ).toEqual({ …initialState, board: createBoard(- - X - - - -), }); });

Slide 126

Slide 126

1 it(“allows a player to make a move”, () => { 2 const { getByTitle } = render(<Game />); 3 const spot = getByTitle(“0”); 4 5 fireEvent.click(spot); 6 7 expect(getByTitle(“0”).textContent).toEqual(” 8 }); “);

Slide 127

Slide 127

1 it(“allows a player to make a move”, () => { 2 const { getByTitle } = render(<Game />); 3 const spot = getByTitle(“0”); 4 5 fireEvent.click(spot); 6 7 expect(getByTitle(“0”).textContent).toEqual(” 8 }); “);

Slide 128

Slide 128

1 it(“allows a player to make a move”, () => { 2 const { getByTitle } = render(<Game />); 3 const spot = getByTitle(“0”); 4 5 fireEvent.click(spot); 6 7 expect(getByTitle(“0”).textContent).toEqual(” 8 }); “);

Slide 129

Slide 129

@beccaliz

Slide 130

Slide 130

@beccaliz

Slide 131

Slide 131

Local State @beccaliz

Slide 132

Slide 132

@beccaliz

Slide 133

Slide 133

Prop Drilling @beccaliz

Slide 134

Slide 134

Prop Drilling Duplication @beccaliz

Slide 135

Slide 135

@beccaliz

Slide 136

Slide 136

✨ Higher Order Components ✨ @beccaliz

Slide 137

Slide 137

✨ Higher Order Components ✨ ✨ Render Props ✨ @beccaliz

Slide 138

Slide 138

1 <ModalManager> 2 {({ showModal, hideModal, visible }) => ( 3 <React.Fragment> 4 <Button onClick={() => showModal()}>Click me!</Button> 5 <Modal visible={visible}> 6 <h1>You win!</h1> 7 <Button onClick={() => hideModal()}>Close</Button> 8 </Modal> 9 </React.Fragment> 10 )} 11 </ModalManager>

Slide 139

Slide 139

1 <ModalManager> 2 {({ showModal, hideModal, visible }) => ( 3 <React.Fragment> 4 <Button onClick={() => showModal()}>Click me!</Button> 5 <Modal visible={visible}> 6 <h1>You win!</h1> 7 <Button onClick={() => hideModal()}>Close</Button> 8 </Modal> 9 </React.Fragment> 10 )} 11 </ModalManager>

Slide 140

Slide 140

1 const ModalManager = ({ children }) => { 2 const [visible, setVisible] = React.useState(false); 3 4 function showModal() { 5 setVisible(true) 6 }; 7 8 function hideModal { 9 setVisible(false) 10 }; 11 12 render() { 13 return ( 14 <React.Fragment> 15 {children({ visible, showModal, hideModal })} 16 </React.Fragment> 17 ) 18 } 19 }

Slide 141

Slide 141

1 const ModalManager = ({ children }) => { 2 const [visible, setVisible] = React.useState(false); 3 4 function showModal() { 5 setVisible(true) 6 }; 7 8 function hideModal { 9 setVisible(false) 10 }; 11 12 render() { 13 return ( 14 <React.Fragment> 15 {children({ visible, showModal, hideModal })} 16 </React.Fragment> 17 ) 18 } 19 }

Slide 142

Slide 142

1 <Query query={LOGGED_IN_USER}> 2 {({ loading, error, data }) => { 3 if (loading) { 4 return <Spinner />; 5 } 6 if (error) { 7 return <Error message={error} />; 8 } 9 return <Profile user={data}/>; 10 }} 11 </Query>

Slide 143

Slide 143

1 <Query query={LOGGED_IN_USER}> 2 {({ loading, error, data }) => { 3 if (loading) { 4 return <Spinner />; 5 } 6 if (error) { 7 return <Error message={error} />; 8 } 9 return <Profile user={data}/>; 10 }} 11 </Query>

Slide 144

Slide 144

1 <Query query={LOGGED_IN_USER}> 2 {({ loading, error, data }) => { 3 if (loading) { 4 return <Spinner />; 5 } 6 if (error) { 7 return <Error message={error} />; 8 } 9 return <Profile user={data}/>; 10 }} 11 </Query>

Slide 145

Slide 145

1 <Query query={LOGGED_IN_USER}> 2 {({ loading, error, data }) => { 3 if (loading) { 4 return <Spinner />; 5 } 6 if (error) { 7 return <Error message={error} />; 8 } 9 return <Profile user={data}/>; 10 }} 11 </Query>

Slide 146

Slide 146

1 <Container> 2 <Query query={LOGGED_IN_USER}> 3 {({ loading, error, data }) => { 4 if (data) { 5 return ( 6 <ModalManager> 7 {({ showModal, hideModal, visible }) => { 8 return ( 9 <React.Fragment> 10 <Button onClick={() => showModal()}>Click me!</Button> 11 {visible && ( 12 <Modal> 13 <h1>Hello {data.user.name}!</h1> 14 <Button onClick={() => hideModal()}>Close</Button> 15 </Modal> 16 )} 17 </React.Fragment> 18 ); 19 }} 20 </ModalManager> 21 ) 22 } 23 }} 24 </Query> 25 </Container>

Slide 147

Slide 147

1 <Container> 2 <Query query={LOGGED_IN_USER}> 3 {({ loading, error, data }) => { 4 if (data) { 5 return ( 6 <ModalManager> 7 {({ showModal, hideModal, visible }) => { 8 return ( 9 <React.Fragment> 10 <Button onClick={() => showModal()}>Click me!</Button> 11 {visible && ( 12 <Modal> 13 <h1>Hello {data.user.name}!</h1> 14 <Button onClick={() => hideModal()}>Close</Button> 15 </Modal> 16 )} 17 </React.Fragment> 18 ); 19 }} 20 </ModalManager> 21 ) 22 } 23 }} 24 </Query> 25 </Container>

Slide 148

Slide 148

1 <Container> 2 <Query query={LOGGED_IN_USER}> 3 {({ loading, error, data }) => { 4 if (data) { 5 return ( 6 <ModalManager> 7 {({ showModal, hideModal, visible }) => { 8 return ( 9 <React.Fragment> 10 <Button onClick={() => showModal()}>Click me!</Button> 11 {visible && ( 12 <Modal> 13 <h1>Hello {data.user.name}!</h1> 14 <Button onClick={() => hideModal()}>Close</Button> 15 </Modal> 16 )} 17 </React.Fragment> 18 ); 19 }} 20 </ModalManager> 21 ) 22 } 23 }} 24 </Query> 25 </Container>

Slide 149

Slide 149

1 <Container> 2 <Query query={LOGGED_IN_USER}> 3 {({ loading, error, data }) => { 4 if (data) { 5 return ( 6 <ModalManager> 7 {({ showModal, hideModal, visible }) => { 8 return ( 9 <React.Fragment> 10 <Button onClick={() => showModal()}>Click me!</Button> 11 {visible && ( 12 <Modal> 13 <h1>Hello {data.user.name}!</h1> 14 <Button onClick={() => hideModal()}>Close</Button> 15 </Modal> 16 )} 17 </React.Fragment> 18 ); 19 }} 20 </ModalManager> 21 ) 22 } 23 }} 24 </Query> 25 </Container>

Slide 150

Slide 150

1 <Container> 2 <Query query={LOGGED_IN_USER}> 3 {({ loading, error, data }) => { 4 if (data) { 5 return ( 6 <ModalManager> 7 {({ showModal, hideModal, visible }) => { 8 return ( 9 <React.Fragment> 10 <Button onClick={() => showModal()}>Click me!</Button> 11 {visible && ( 12 <Modal> 13 <h1>Hello {data.user.name}!</h1> 14 <Button onClick={() => hideModal()}>Close</Button> 15 </Modal> 16 )} 17 </React.Fragment> 18 ); 19 }} 20 </ModalManager> 21 ) 22 } 23 }} 24 </Query> 25 </Container>

Slide 151

Slide 151

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Game.js function mapStateToProps({ board }) { return board; } function mapDispatchToProps(dispatch) { return { makeMove: (index) => { dispatch(makeMove(index)); } }; } export default connect( mapStateToProps, mapDispatchToProps )(Game);

Slide 152

Slide 152

1 export default withRouter( 2 withTheme( 3 withSomeOtherState( 4 connect( 5 mapStateToProps, 6 mapDispatchToProps 7 )(Game) 8 ) 9 ) 10 );

Slide 153

Slide 153

1 export default withRouter( 2 withTheme( 3 withSomeOtherState( 4 connect( 5 mapStateToProps, 6 mapDispatchToProps 7 )(Game) 8 ) 9 ) 10 );

Slide 154

Slide 154

1 export default withRouter( 2 withTheme( 3 withSomeOtherState( 4 connect( 5 mapStateToProps, 6 mapDispatchToProps 7 )(Game) 8 ) 9 ) 10 );

Slide 155

Slide 155

1 export default withRouter( 2 withTheme( 3 withSomeOtherState( 4 connect( 5 mapStateToProps, 6 mapDispatchToProps 7 )(Game) 8 ) 9 ) 10 );

Slide 156

Slide 156

✨ Context ✨ @beccaliz

Slide 157

Slide 157

@beccaliz

Slide 158

Slide 158

provider state @beccaliz helpers

Slide 159

Slide 159

provider state helpers view @beccaliz

Slide 160

Slide 160

provider state helpers view consumer @beccaliz

Slide 161

Slide 161

provider state helpers view consumer @beccaliz

Slide 162

Slide 162

@beccaliz

Slide 163

Slide 163

@beccaliz

Slide 164

Slide 164

context provider @beccaliz

Slide 165

Slide 165

@beccaliz

Slide 166

Slide 166

@beccaliz

Slide 167

Slide 167

context provider @beccaliz

Slide 168

Slide 168

1 // GreetingModal.js 2 function GreetingModal() { 3 const { user } = React.useContext(LoggedInUserContext); 4 const { hideModal } = React.useContext(ModalContext); 5 6 return ( 7 <Modal id=”greeting”> 8 <h1>Hello {user.name}!</h1> 9 <Button onClick={() => hideModal()}>Close</Button> 10 </Modal> 11 ) 12 }

Slide 169

Slide 169

1 // GreetingModal.js 2 function GreetingModal() { 3 const { user } = React.useContext(LoggedInUserContext); 4 const { hideModal } = React.useContext(ModalContext); 5 6 return ( 7 <Modal id=”greeting”> 8 <h1>Hello {user.name}!</h1> 9 <Button onClick={() => hideModal()}>Close</Button> 10 </Modal> 11 ) 12 }

Slide 170

Slide 170

1 const ModalProvider = ({ children }) => { 2 const [visible, setVisible] = React.useState(false); 3 4 function showModal() { 5 setVisible(true) 6 }; 7 8 function hideModal { 9 setVisible(false) 10 }; 11 12 render() { 13 return ( 14 <ModalContext.Provider values={{ visible, showModal, hideModal }}> 15 {children} 16 </ModalContext.Provider> 17 ); 18 } 19 }

Slide 171

Slide 171

1 const ModalProvider = ({ children }) => { 2 const [visible, setVisible] = React.useState(false); 3 4 function showModal() { 5 setVisible(true) 6 }; 7 8 function hideModal { 9 setVisible(false) 10 }; 11 12 render() { 13 return ( 14 <ModalContext.Provider values={{ visible, showModal, hideModal }}> 15 {children} 16 </ModalContext.Provider> 17 ); 18 } 19 }

Slide 172

Slide 172

✨ Hooks ✨ @beccaliz

Slide 173

Slide 173

1 // reducers/game.js 2 function useGame(initialState) { 3 const [game, dispatch] = React.useReducer(gameReducer); 4 5 function makeMove(index) { 6 return dispatch({ type: “MAKE_MOVE”, payload: index }) 7 } 8 9 return { game, makeMove }; 10 }

Slide 174

Slide 174

1 // reducers/game.js 2 function useGame(initialState) { 3 const [game, dispatch] = React.useReducer(gameReducer); 4 5 function makeMove(index) { 6 return dispatch({ type: “MAKE_MOVE”, payload: index }) 7 } 8 9 return { game, makeMove }; 10 }

Slide 175

Slide 175

1 // reducers/game.js 2 function useGame(initialState) { 3 const [game, dispatch] = React.useReducer(gameReducer); 4 5 function makeMove(index) { 6 return dispatch({ type: “MAKE_MOVE”, payload: index }) 7 } 8 9 return { game, makeMove }; 10 }

Slide 176

Slide 176

1 function gameReducer(state, action) { 2 switch (action.type) { 3 case “MAKE_MOVE”: { 4 const index = action.payload; 5 const { currentPlayer, players } = state; 6 const nextPlayer = switchPlayer(currentPlayer, players); 7 return { 8 …state, 9 board: { 10 [index]: currentPlayer.marker, 11 currentPlayer: nextPlayer, 12 //…etc 13 } 14 }; 15 } 16 default: { 17 return state; 18 } 19 } 20 }

Slide 177

Slide 177

it(“allows a player to make a move”, () => { const { getByTitle } = render(<Game />); const spot = getByTitle(“0”); fireEvent.click(spot); expect(getByTitle(“0”).textContent).toEqual(” }); “);

Slide 178

Slide 178

Do you need Redux?

Slide 179

Slide 179

Complexity @beccaliz

Slide 180

Slide 180

MobX? @beccaliz

Slide 181

Slide 181

@beccaliz

Slide 182

Slide 182

@beccaliz

Slide 183

Slide 183

@beccaliz

Slide 184

Slide 184

@beccaliz

Slide 185

Slide 185

How do we choose? @beccaliz

Slide 186

Slide 186

You don’t have to choose just one. @beccaliz

Slide 187

Slide 187

What is the scope of the state? @beccaliz

Slide 188

Slide 188

Is there a commonly-used library that can help? @beccaliz

Slide 189

Slide 189

Am I repeating myself? @beccaliz

Slide 190

Slide 190

Incremental Changes @beccaliz

Slide 191

Slide 191

@beccaliz

Slide 192

Slide 192

@beccaliz

Slide 193

Slide 193

@beccaliz

Slide 194

Slide 194

@beccaliz

Slide 195

Slide 195

@beccaliz

Slide 196

Slide 196

@beccaliz

Slide 197

Slide 197

@beccaliz

Slide 198

Slide 198

@beccaliz

Slide 199

Slide 199

@beccaliz

Slide 200

Slide 200

@beccaliz

Slide 201

Slide 201

The Newbie @beccaliz

Slide 202

Slide 202

The Loyalist @beccaliz

Slide 203

Slide 203

The Explorer @beccaliz

Slide 204

Slide 204

✨ Thank you!! ✨ @beccaliz becca.is Slides: