Skip to content

Instantly share code, notes, and snippets.

@JasonStoltz
Last active January 17, 2017 20:29
Show Gist options
  • Save JasonStoltz/c5809d92ebf854df7ee332a1374f1233 to your computer and use it in GitHub Desktop.
Save JasonStoltz/c5809d92ebf854df7ee332a1374f1233 to your computer and use it in GitHub Desktop.
React Patterns

React and Redux patterns

Topics:

  • Smart and Dumb components
  • Stateless Functional components
  • Pure Components
  • Redux
  • Containers and Components
  • mapStateToProps and mapDispatchToProps
  • Selectors
  • Async action
  • Data fetching in Redux
  • Higher Order Components
  • "Sagas"
  • Project Structure
  • Modeling state
  • Reusing reducers

Smart and Dumb components

  • Separation of view and logic
  • Easier for someone to build and style, then "wire up" after the fact
  • Modularity -- Reusability, testing, clarity

Stateless Functional components

  • Once you've boiled down a dumb component far enough, no need for lifecycle, etc., just need a pure function
  • Limitations - No type checking, can't implement "shouldComponentUpdate"

Pure Components

  • By default, React re-renders every time state changes
  • shouldComponentUpdate let's us only re-render when prop values have actually changed
  • ImmutableJS let's us performantly check whether values have changed
  • Stateless functional can't use "Pure Components" pattern because they can't check shouldComponentUpdate
  • Bind function in the constructor, not in render

Redux

  • Manages complexity
    • Simplifies sharing state across the app ... like if you have an Order component, and a Totals component in the nav
    • If storing Order data in Order component, you've now got a mess
    • Could store at top level component as plain old state, but then everything needs to be passed down the entire chain to sub-components as props. With Redux, just wrap a component in "connect"
  • Enforces immutable state ... all changes to state MUST go through actions
  • Debugging and history
  • Modularity ... keeps a lot of logic out of components

mapStateToProps and mapDispatchToProps

  • Cleaner to encapsulate all store interaction here

Containers and Components

  • Redux "Smart Component"
  • Export 2 things to simlify testing

Selectors

  • Example of something that is super simplified by selectors
  • Performance gains from memoization
  • jedwatson.github.io/react-select/

------- END OF FIRST SESSION HERE -------

Async actions

  • Keep promises out of components
  • Redux thunk
  • Have access to entire state
    • Don't need to pull data into components, just to pass it to an action
    • i.e., if you need user data to load an order from an order component
    • Can make decisions based on entire state tree, not just a slice, unlike in a reducer
  • Have access to dispatch
    • Can dispatch a bunch of other action
  • With great power comes great responsibility: http://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/
    • Avoid over dispatching.
    • Think of each action as a "transaction" ... don't dispatch multiple actions that would leave state in a weird "in-between" state.
    • Some people think you should avoid using getState... but it's up for debate

Data fetching

Higher Order Components

  • Example from shift-publish

"Sagas"

There is a lot of confusing in the frontend world on how some backend concepts like CQRS / EventSourcing and Flux / Redux may be related, mostly because in Flux we use the term "action" which can sometimes represent both imperative code (LOAD_USER) and events (USER_LOADED). I believe that like event-sourcing, you should only dispatch events.

Your code becomes much more testable as the effects are declarative

You don't need anymore to trigger rpc-like calls like actions.loadUser(). Your UI just needs to dispatch what HAS HAPPENED. We only fire events (always in the past tense!) and not actions anymore.

For example imagine an infinite scroll view. CONTAINER_SCROLLED can lead to NEXT_PAGE_LOADED, but is it really the responsibility of the scrollable container to decide whether or not we should load another page? Then he has to be aware of more complicated stuff like whether or not the last page was loaded successfully or if there is already a page that tries to load, or if there is no more items left to load? I don't think so: for maximum reusability the scrollable container should just describe that it has been scrolled. The loading of a page is a "business effect" of that scroll

i.e., If you need to load a profile when a user name is clicked ... dispatch "USER_NAME_CLICKED" when user name is clicked and call "loadProfile" in action creator, instead dispatching "LOAD_PROFILE" directly

  • If you structure your project this way, you basically end up with 2 types of actions that can be dispatched ... sagas and actions.

Project Structure

  • Feature vs Function
  • Keeping state and actions seperated from components seems to be a good idea, to avoid circular dependencies between modules

Modeling state

Reusing reducers

Data fetching Invalidating -

  • one way data flow + calls are always made at the same place and you don’t need to make explicit call from somewhere weird
  • Reducer best practices
  • Storing data in a Map of ids
  • Editing nested data

Redux Thunk — actions say “What happened”, sagas say “Do this” MapStateToProps with Selectors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment