# Concurrent React, Redux and State Management ## Concurrent React ### Time Slicing - Prevent blocking ``` * setState * start render * render yield | | * some other event handler | * render continue * render yield | | * some other event handler | * render continue * render finish ``` - Prioritized reconciling ``` * (low priority event) | * setState * start render * render yield | | * (high priority event) | | | * setState | * render start | | | * finish render | * re-apply state change * render ``` ### Suspense - Throwing Promises - Placeholders - `maxDuration` ``` * (event) | * setState * start render * render throw promise . . . * (event) . | . * setState . * render start . * finish render . . . . * promise resolve * re-aplly state change * render ``` ## Consequences - React is in charge of state - Ensures consistent state for tree across time slices (no "tearing") - "Work in progress" state ## Redux - v5: Strore via Context - v6: State (and Store) via Context - Push vs Pull ``` | REDUX STORE | * (low priority event) | { users: [] } | | * dispatch | * store change | { users: [a,b,c] } * Provider#setState | * render start | * render yield | | | | * (high priority event) | | | | | * dispatch | | * store change | { expanded: true, users: [a,b,c] } | * Provider#setState | | * render start | | | | x | cancel render | | | * finish render | ``` Component State > Global State ## Caching External Data - Prevent re-fetching data - Take advantage of concurrent rendering mode - Prevent tearing ### Component State? - Data lost on unmount - Does not work with suspense ### Global Singleton? - Risk of tearing ### `Context.write` https://github.com/reactjs/rfcs/pull/89 React managed state outside the component tree ``` const Context = React.createContext(defaultValue); function Component() { return ( {value => /* render something ... */} ); } ``` ``` const Context = React.createContext(initialValue, contextDidUpdate); Context.write(newValue); Context.write(prevValue => newValue); ``` ``` const Store = React.createContext(initialState); export function dispatch(action) { Store.write(state => reducer(state, action)); } export function useStore() { return useContext(Store); } ``` ``` | Context | * (low priority event) | * { users: [] } | | | * dispatch | |\ * Context.write | * \ { users: [a,b,c] } * render start | | \ * render yield | | | | | | | | * (high priority event) | | | | | | | | | * dispatch | | | | * Context.write | | * { expanded: true, users: [] } | * render start | | / | * finish render | | / * | |/ * re-apply state changes | * { expanded: true, users: [a,b,c] } * render ``` Dependency Injection/Testing ``` ``` ## Let Others Take Care of It - React Apollo - Unstated - Relay? ## Thanks! github.com/tf @tfischbach www.codevise.de ## References https://www.youtube.com/watch?v=nLF0n9SACd4 https://blog.isquaredsoftware.com/2018/11/react-redux-history-implementation/ https://github.com/reduxjs/react-redux/issues/890 https://github.com/reduxjs/react-redux/pull/1000 https://github.com/reactjs/rfcs/pull/89