Flux, React and Redux

June 29, 2018

Tags:

React is declarative.

An advantage vue.js has over react is that react requires JSX and JSX mangles up the data and operations.

React Component class or react component type

A component takes parameters called props, short for properties, and returns a hierarchy of views to display via the render method.

In Haskell speak it's as if a render is a functor and component is fmap.

component :: render -> props ->  hierarchy of views

render returns a description of what you wish to render react takes the description and renders it to a screen render returns a react element (a lightweight description of what to render)

Each React element is a real JavaScript object that you can store in a variable or pass around your program.

React components can have state by setting this.state in the constructor, which should be considered private to the component.

In JavaScript classes, you need to explicitly call super(); when defining the constructor of a subclass.

We even have a topic on lifting state

When you want to aggregate data from multiple children or to have two child components communicate with each other, move the state upwards so that it lives in the parent component.

The parent can then pass the state back down to the children via props, so that the child components are always in sync with each other and with the parent

It is conventional in React apps to use on* names for the attributes and handle* for the handler methods.

Controlled components child components that receive their state from a parent component.

React components are made up of react elements which so far look just like HTML elements to me.

rendering

Imperative rendering

React comes in here: re renders diffs

From: A Case against the GO TO Statement by Edward Dijkstra

we should do (as wise programmers aware of our limitations) our utmost best to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between the program (spread out in text space) and the process (spread out in time) as trivial as possible.

Make things snapshottable:

  • one state to next state

When data changes react re renders entire component

referentially transparent functions/endpoints

  • trivial to predict for given input
  • easy to test

Stateful DOM or any stateful UI toolkit

Solution is a virtual DOM which is implemented in a lib called react

immutability plays well with diffing two states

Functional components

Rather than return a class extending React.Component, write a fn that takes props and returns what should be rendered.

state

State is similar to props, but it is private and fully controlled by the component. Local state is exactly that: a feature available only to classes.

State updates may be asynchronous

React may batch multiple setState() calls into a single update for performance. Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

to fix this use a version of setState that accepts a function e.g

this.setState((prevState, props) => {
  counter: prevState.counter + props.increment
});

State updates are merged

merges the object you provide into the current state. merging is shallow i.e. leaves other key value pairs untouched

Handling events

When using React you should generally not need to call addEventListener to add listeners to a DOM element after it is created. Instead, just provide a listener when the element is initially rendered.

You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.

Understanding JavaScript Bind ()

You can use an arrow fn in the callback e.g onClick={(e) => this.handleClick(e)}

The problem with this syntax is that a different callback is created each time the LoggingButton renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.

Lifecycle hooks

Methods run during the life cycle events such as mounting and umounting

  • componentDidMount: runs after the component output has been rendered to the DOM.
  • componentWillUnmount:

this.setState({}) takes an object of new state constructor runs before the object is created

modifying state directly e.g this.state.comment = "I'm new..." doesn't lead to a rerender. use set state

The only place where you can assign this.state is the constructor.

Read more under:

  • React.Component https://reactjs.org/docs/react-component.html

kaznet

App.js has all the paths triggers container for that component

Hooks

From Kent C. Dotts videos 13-19 Used to maintain component state

React.useState

Takes the initial value. Returns an array containing the name and a setter for the name.

function MyComponent() {
  const [name, setName] = React.useState('');
  const handleChange = event => setName(event.target.value);

  const [name2, setName2] = React.useState('');
  const handleChange2 = event => setName(event.target.value);
  

  return (
    <div>

      <form>
        <!-- htmlFor is like for in html for but JSX-->
        <label htmlFor="name""></label>
        <input id="name" onChange={handleChange}></input>
      </form>
      {name ? <strong>Helllo {name}</strong> : <span>Please type in name</span>}
      
      <form>
        <!-- htmlFor is like for in html for but JSX-->
        <label htmlFor="name2""></label>
        <input id="name2" onChange={handleChange2}></input>
      </form>
      {name2 ? <strong>Yes? {name}</strong> : <span>Please type in name</span>}

    </div>
  )
}

React.useEffect

A react hook that lets us do things that have side effects e.g save value to localStorage.

useEffect takes a lambda and an array of dependencies where we pass what we want to sync the state of the world with the state of our app.

Check the dependency array with eslint-plugin-react-hooks to keep the array up to date.

function MyComponent() {
  // First get what's in localStorage
  const [name, setName] = React.useState(
    /* pass a lambda here to make this initialization lazy
       it will only be called to fetch the intiial value and not in 
       re-renders
     */
    () => window.localStorage.getItem('name') || ''
  );
  
  const handleChange = event => setName(event.target.value);

  // in this case we want to store only name
  React.useEffect(() => {
    window.localStorage.setItem('name', name);
  }, [name]);

  const [name2, setName2] = React.useState('');
  const handleChange2 = event => setName(event.target.value);
  

  return (
    <div>
      <form>
        <!-- htmlFor is like for in html for but JSX-->
        <label htmlFor="name""></label>
        <input id="name" onChange={handleChange}></input>
      </form>
      {name ? <strong>Helllo {name}</strong> : <span>Please type in name</span>}
      
      <form>
        <!-- htmlFor is like for in html for but JSX-->
        <label htmlFor="name2""></label>
        <input id="name2" onChange={handleChange2}></input>
      </form>
      {name2 ? <strong>Yes? {name}</strong> : <span>Please type in name</span>}
    </div>
  )
}

The localStorage pattern is common so there's an npm package for it that has an API like the following:

function useLocalStorage(key, defaultValue='') {
  const [state, setState] = React.useState(
    () => window.localStorage.getItem(key) || defaultValue
  );

  React.useEffect(() => {
    window.localStorage.setItem(key, state);
  }, [state]);

  return [state, setState]
}

function MyComponent() {
  const [name, setName] = useLocalStorage('name', '');
  const handleChange = event => setName(event.target.value);
  
  return (
    <div>
      <form>
        <!-- htmlFor is like for in html for but JSX-->
        <label htmlFor="name""></label>
        <input id="name" onChange={handleChange}></input>
      </form>
      {name ? <strong>Helllo {name}</strong> : <span>Please type in name</span>}
    </div>
  )
}

It's convention to have custom hooks begin with use that way eslint-plugin-react-hooks can check out custom hooks for mistakes.

React.useRef

A ref is a reference to the DOM node created by react. To get it we use React.useRef

A ref is an object with a mutable current property

function Tild({children}) {
  const tiltRef = React.useRef();
  
  /*
    This code runs after react has updated the DOM
    Interacting with the DOM is impure so we use a useRef hook
   */
  React.useEffect(() => {
   console.log(tiltRef.current)
   // tiltNode is our DOM node with class name my-class
   tiltNode = tiltRef.current
   
   // We may need to clean up our DOM node.
   // Ran when the component is unmounted from the page
   return () => {
     tiltNode.vanillaTilt.destroy()
   }
  }, []); // the empty dependency array makes us not run useEffect between re-renders.
  
  return (
    <div ref={tiltRef} className="my-class">
    ...
    </div>
  )
}

Flux

Flux architecture for building UIs using react.

Think of flux as new MVC

  • action: comes into the system
  • dispatcher: traffic controller for the whole thing
  • store: data layer updates whenever we get a new action
  • view: re render whenever store says something has changed

Difference from MVC

  • use explicit data instead of derived data
  • separate data from view state
  • avoid cascading effects by preventing nested updates
    • x updates y which updates z
    • let data layer completely finish processing before triggering any additional actions

single direction flow:

flux

the dispatcher ensures that until store is done views or anything else can't put an action through the system

advantages:

  • improved data consistency: everything in sync
  • easier to pinpoint root of a bug
  • easier unit tests because modules are pure-ish/atomic/functional

views

can trigger actions

dispatcher

enforces no cascading effects once an action goes into store you can't put another until store is done processing it

Hackernooon post summary

An implementation of the Flux architecture— a pattern for passing data around in a React app.

Under classic Flux, app state is held within stores. Dispatched actions cause this state to change, afterwhich the views that listen to these state changes will re-render themselves accordingly

Flux

Redux

Dir structure

  • /src/component/ Dumb React components that have no knowledge of Redux
  • /src/containers/ Smart React components that are connected to our Redux store
  • /src/services Abstraction facades for external API (like backend servers)
  • /src/store All Redux-specific code goes here, including all business-logic of our app

The store directory is organized by domain, each containing:

  • /src/store/{domain}/reducer.js Reducer as a default export with all selectors as named exports
  • /src/store/{domain}/actions.js All the domain action handlers (thunks and plain object creators)

The reducer holds the state and updates it.

Rules:

  • Smart components are not allowed to have any logic except dispatching actions.
  • Services must be completely stateless.
  • Smart components should always access state through selectors.
  • Minimize view logic in smart components by extracting it into dumb components.
  • Place all business logic inside action handlers (thunks), selectors and reducers.

Selectors

A selector is a pure function that takes the global state as argument and returns some transformation over it Selectors are tightly coupled to reducers and are located inside reducer.js

Redux

Redux has no relation to react but works especially well with it because react let's you describe the UI as a function of state. Redux emits state updates in response to actions.

Redux docs

actions

pure functions in redux only 2 things allowed to interact with the store one is a reducer it changes the state others are selectors retrieve data from the state

containers are components aware of global state

all things that fetch lists should be aware of pagination

page numbers

generic for tasks, locations clients

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

Connects a React component to a Redux store. connect is a facade around connectAdvanced, providing a convenient API for the most common use cases.

It doesn't modify the component class passed to it; instead it returns a new, connected component class for you to use.

References

mapStateToProps

The result must be a plain object which will be merged into the component's props.

mapDispatchToProps

Provider

To allow all components to access the store use a special react redux component to make the store available to all container components in the app without passing it explicitly.

Read more:

Action creator

A function that creates an action.

action is a payload of information, and an action creator is a factory that creates an action.

Calling an action creator only produces the action but does not dispatch it. You need to call the store's dispatch fn to actually cause the mutation

Reducer

Also called a reducing function function that accepts an accumulation and a value and returns a new value

reduce in other langs or fold in haskell.

reduce a collection of values into a single values

most important concept in redux

combineReducers

A helper function that turns an object whose values are different reducing functions into a single reducing fn you can pass to createStore.

the resulting reducer calls every child reducer and gethers the resilt into a single state object

The state produced by combineReducers() namespaces the states of each reducer under their keys as passed to combineReducers().

createStore

creates a single redux store that holds the complete state of your app.

Your app should have a single store

args: reducer, preloadedState, enhancer

enhancer: store enhancer optionally specify it to enhance the store with third party capabilities such as middleware, time travel, persistence etc

the only store enhancer that ships with redux is applyMiddleware.

applyMiddleware

Lets you wrap the store's dispatch method Middleware is composable

Most common use case is to support async actions without much boilerplate code or lib dependency. Does so by letting you dispatch async actions in addition to normal actions.

https://redux.js.org/api/applymiddleware

thunk-redux

lets the action creators invert control by dispatching functions. They would receive dispatch as an arg and may call it async. Such functions are called thunks.

redux-promise

Lets you dispatch a promise async action and dispatches a normal action when the promise resolves.

Middleware is not baked into createStore and is not a fundamental part of the Redux architecture, but we consider it useful enough to be supported right in the core. This way, there is a single standard way to extend dispatch in the ecosystem, and different middleware may compete in expressiveness and utility.

Async action

A value that is sent to a dispatching function but not yet ready for consumption by the reducer. It will be transformed by middleware into an action before being sent to the base dispatch fn.

Store

Holds the whole state tree of your app. A store is not a class. It's just an object with a few methods on it.

There's no way to directly modify the store only way is through reducers and only way to trigger reducers is to dispatch actions.

to change data dispatch and action to obtain data we should (need to) go through a selector

we get the state of the application at the time we made the select

Components

Smart components are not allowed to have any logic except dispatching actions. Smart components should always access state through selectors.

Place all business logic inside action handlers (thunks), selectors and reducers.

Presentational and container components

reference: Medium---Presentational and Container Components aka stateful and pure components among other names

This approach achieves:

  • separation of concerns
  • reusability

Services

Abstract an external API

services must be stateless

State

In Redux, the reducer is the construct that holds state and updates it

Resources

Hackernoon---Redux Step by Step: A Simple and Robust Workflow for Real Life Apps

Service workers

Appendix

  • thunk: a function that takes no argument not like a haskell thunk.

Other implementions of the store

  • backbone: instagram