To summarize, it’s basically code that follows the tutorial.

Redux

  • The core source code is concise
  • It solves the data processing problem of multi – interaction and multi – data source
  • Application scenario: Component status sharing, one component needs to change the global status, one component needs to change the status of another component
  • Similar to VUEX, it is actually a data transit zone

The problem

  • We can see that sharing using an object data, in which the shared state can be arbitrarily modified, the behavior of the program becomes very unpredictable. So we raised the bar for modifying the data: everyone had to passdispatchTo perform the modification, and you need to conspicuously pass it an action objectaction.
  • It turns out that every time you modify the data, you have to render manually: using sub-pub mode, throughstore.subscribeSubscribe to data render events that automatically render views every time data is updated
  • The performance of “re-render view” was found to be poor, so “Objects of shared structure” was introduced to solve the problem. Just make simple judgments at the beginning of each render function to avoid repeating the same data.
  • To optimize thestateChangerReducer is a pure function defined as reducer, whose function is responsible for initializationstateAnd according to thestateandactionCompute new with shared structuresstate.

Redux exists to solve the problem of accessing shared data and providing an API to modify it.

The core concept

  1. Store: storage container
  2. State: stores basic data snapshots.
  3. Action: To update the data in state, initiate an action
  4. Reducer: Series actions and states so that we can do an action on a state and return the new state.

Updating the state according to the Action object is the whole idea of Redux.

The three principles

  1. Single data source: The state of the entire application is stored in an object tree that exists in a single store.
  2. State is read-only: the only way to change State is to trigger an action, which is a generic object that describes events that happen easily.
  3. Use pure functions to modify (with parameters state and Action) : To describe how the action changes the State Tree, you need to write reducers. It accepts the previous state and action and returns the new state, i.e(state, action) => state.

Redux design idea

  1. A Web application should be a state machine: there is a one-to-one correspondence between views and states
  2. All states are stored in one object

The basic concept

Store

The object that stores the data can be thought of as a container, and there can only be one Store for the entire application.

import {createStore} from 'redux'
const store = createStore(fn) // Store is an object with two keys, getState and dispatch. Its corresponding value is a function (getState() has no argument, and dispatch(action) is a JS object describing the action).
Copy the code
  • fnStateChanger is a function called stateChanger with a list of arguments (state, action) to usePerform the action on the current state
  • CreateStore returns an object of the form {getState: ()=> state, dispatch: (action) => stateChanger(state, action)}

State

Represents a data snapshot of a node at a certain time. You can get the current State by calling store.getState().

Action

State changes need to be handled through Action. An Action usually has a name of Type and a payload of information it carries.

  • To simplify Action generation, you can use a function that returns an Action object, called Action Creator

Basic API

store.getState()

Get current State

store.dispatch()

Is the only way to issue an Action in a View. Keep the data up to date and the page rendered up to date through the publish-subscribe model.

store.subscribe()

  • Store allows usestore.subscribeMethod sets a listener function that is automatically executed whenever State changes. So simply put the component’s render function (render/setState) into the listener to implement automatic rendering of the page.
  • store.subscribeReturns a function that can be called to unlisten.

reducer()

When the Store receives the Action, it calculates the new State from both the State and the Action. If no State is received, an initial data is returned.

Reducer is a pure function, so the same State and Action must have the same result.

The context of the React. Js

A component can use the getChildContext method to return an object that defines the context of the subcomponent tree. The component providing the context must provide childContextTypes as the declaration and validation of the context. Child components can access data in this object through this.context.

.

Pure Function Pure Function

A function whose returns depend only on its arguments and have no side effects during execution is called a pure function.

  1. Returns results only depending on its own parameters
  2. There are no side effects
  • Pure functions are very strict, we can do almost nothing but calculate data, and we can’t rely on data other than parameters when we calculate.
  • Meaning: Very reliable, no unexpected behavior, no external impact. Convenient debugging and testing.

Objects that share a structure

ES6’s extended operators can be used for shallow copies of objects.

const obj = { a: 1.b : 2 }
constobj2 = { ... obj,b : 3.c: 4 } {a: 1, b: 3, c: 4}, the new b overwrites the old B
Copy the code

Compile Reducer habits

  1. Define the action types
  2. Write the reducer
  3. Action Creators related to this Reducer

Redux template writing

// Define a reducer
function reducer (state, action) {
    /* Initialize state and switch case */
}

/ / store
const store = createStore(reducer)

// Listen for data changes and re-render the page
store.subscribe(() = > renderApp(store.getState()))

Render the page for the first time
renderApp(store.getState())

// Now you can dispatch some actions, and the page will update automatically
store.dispatch(...)
Copy the code

Customize a Reducer


 function themeReducer (state, action) {
  if(! state)return {
    themeName: 'Red Theme'.themeColor: 'red'
  }
  switch (action.type) {
    case 'UPDATE_THEME_NAME':
      return {
        ...state,
        themeName: action.themeName
      }
    case 'UPDATE_THEME_COLOR':
      return {
        ...state,
        themeColor: action.themeColor
      }
    default:
      return state
  }
}
Copy the code

Appendix: Code

index.js

If you want to build different stores, just pass a Reducer that can initialize data and execute actions on state.
function createStore (reducer) {
  let state = null
  const listeners = []
  const subscribe = (listener) = > listeners.push(listener)
  const getState = () = > state
  const dispatch = (action) = > {
    state = reducer(state, action) // Overwrite the original object
    listeners.forEach((listener) = > listener())
  }
  dispatch({})
  return { getState, dispatch, subscribe } // This returns a key value, which is the entire contents of the store
}

// The original way
/* function dispatch (action) { switch (action.type) { case 'UPDATE_TITLE_TEXT': appState.title.text = action.text break case 'UPDATE_TITLE_COLOR': appState.title.color = action.color break default: break } } */

// After pulling away, Dispatch only needs to accept the action, and then it is up to stateChanger to change the state
/ / formerly known as stateChanger, new reducer, to carry out the meaning of the action, the current state is a pure function well
function reducer (state, action) {
  if(! state)return {
    title: {
      text: 'the React. Js books'.color: 'red',},content: {
      text: 'React. Js Little book contents'.color: 'blue'}}switch (action.type) {
    case 'UPDATE_TITLE_TEXT':
      return { // Shallow copy does not modify the original data. state,title: {
          ...state.title,
          text: action.text
        }
      }
      // state.title.text = action.text // This will modify the original data
    case 'UPDATE_TITLE_COLOR':
      return {
        ...state,
        title: {
          ...state.title,
          color: action.color
        }
      }
    default:
      return state
  }
}

function renderApp(newAppState, oldAppState={}) {
  if (newAppState === oldAppState) return
  console.log('render app.. ')
  renderTitle(newAppState.title, oldAppState.title)
  renderContent(newAppState.content, oldAppState.content)
}

function renderTitle(newTitle, oldTitle={}) {
  if (newTitle === oldTitle) return 
  console.log('render title- - ')
  const titleDOM = document.getElementById('title')
  titleDOM.innerHTML = newTitle.text
  titleDOM.style.color = newTitle.color
}

function renderContent(newContent, oldContent={}) {
  if (newContent === oldContent) return 
  console.log('render content@ @')
  const contentDOM = document.getElementById('content')
  contentDOM.innerHTML = newContent.text
  contentDOM.style.color = newContent.color
}

// Encapsulate the raw data into a shared repository reducer function (with initialized data) -> store object
const store = createStore(reducer)
let oldState = store.getState()
store.subscribe(() = > {
  const newState = store.getState()
  renderApp(newState, oldState)
  oldState = newState
})

// Because of the publishing-subscribe model, each call to Dispatch executes all listeners (in our case, renderApp), so even if there are dispatches to modify the data, renderApp only needs to be executed once
renderApp(store.getState())
store.dispatch({ type: 'UPDATE_TITLE_TEXT'.text: 'Give me a milkshake please! '})
store.dispatch({ type: 'UPDATE_TITLE_COLOR'.color: 'red'})

Copy the code