redux - (1) the core concepts (state \ action \ reducer), the three principles, todolist with redux

2019-11-19:

Learning Content:

JavaScript is Redux state of the container, providing predictable of state management.


 

 

I. Introduction:

In the following scene, it is wise to introduce Redux:

  • You have quite a lot of changes in data over time
  • Your state needs to have a single source of reliable data
  • Do you think all the state on the top level assembly has been unable to meet the needs of the

Highlights:

  All application state are stored in a single store in the form of an object tree. The only way is to change the state to trigger action, a description of what happens. In order to describe how action to change the state tree, you need to write reducers.

  As applications get larger, you should put the root level reducer split into multiple small reducers, independently operate different parts of the state of the tree, rather than adding new stores. It's like a React use only a root-level component, and the root component is composed of many small components.

motivation:

  Too many of the state (state), state at any time, for any reason, how change is already out of control. Here largely from the complexity: We always difficult to sort out the confusing two concepts together: change and asynchronous . Redux trying to change state becomes predictable.

 

The core concept :( example with todolist)

state:

{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}

action: To update the data in the state, you need to initiate an action. Action is a plain JavaScript object used to describe what happened. action as an indicator of what is described took place.

{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

reduce: To string together the action and the state, the development of some function, which is reducer. receiving state and a reducer just action, and returns the new state of the function . Often it takes several reducers used in combination:

(Two small reducer)

// 改可视的筛选器条件:
function
visibilityFilter(state = 'SHOW_ALL', action) { if (action.type === 'SET_VISIBILITY_FILTER') { return action.filter } else { return state } }
// 对state加入action的操作
function todos(state = [], action) { switch (action.type) { case 'ADD_TODO': return state.concat([{ text: action.text, completed: false }]) case 'TOGGLE_TODO': return state.map((todo, index) => action.index === index ? { text: todo.text, completed: !todo.completed } : todo ) default: return state } }

(Redevelopment of a reducer call these two reducer, and then to manage the entire application state :)

function todoApp(state = {}, action) {
  return {
    todos: todos(state.todos, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  }
}

 

Three principles:

(1) a single source:

  The entire application  state  is stored in an object tree, and the object tree exists only in a single  store  in.

    Redux and do not care how you store state, state may be ordinary objects, immutable objects, or other types.

  state from the server may be serialized and injected into the client without having to write additional code.

  Because it is a single state tree, debugging becomes very easy. In development, you can use the state saved locally, thus speeding up the development speed.  

  Such as "undo / redo" function of such previously difficult to achieve a breeze.

(2) State is read-only, the only change is only action:

  action is the common object is used to describe events that have occurred.

  To ensure that the views and network requests can not directly modify the state, instead they can only express intention want to modify. Because all modifications are centralized processing, and in strict accordance with a sequence one after the execution, there is no fear occurs race condition (race condition) of. Action is just an ordinary objects, so they can be printed journal, serialized, stored, played back late when debugging or testing.

// 上面的action写成dispatch:

store.dispatch({
  type: 'COMPLETE_TODO',
  index: 1
})

store.dispatch({
  type: 'SET_VISIBILITY_FILTER',
  filter: 'SHOW_COMPLETED'
})

(3) the use of pure function to perform modifications (that is, the reducers)

  As applications become larger, you can break it into a plurality of the reducers of small, independently operating different portions of the state tree because only a function of reducer, you can control the order in which they are called, passing in the additional data, and even can be prepared multiplexed reducer to deal with some common tasks, such as a pager.

  reducer should be pure: impure reducer make some development features, such as time travel, recording / playback or heat load can not be achieved . In addition, in most practical applications, the nature of this data is not available and will not bring changes in performance problems, as demonstrated by Om, even if the object allocation fails, you can still prevent expensive re-rendering and re-calculated. The purity, due to changes in the application of the reducer at a glance.

 


 

Second, the basis of:

(1)Action:

  Action data is from the application store the transmitted payloads. It is the only source of store data. Generally you will pass  store.dispatch() the action reached the store.

  We agreed, you must use a string type in the action  type field to indicate the action to be performed . In most cases, type it will be defined as string constants. When applying increasing scale, we recommend using a separate module or to store files action. In addition to  type external fields, structural action object entirely up to you.

  At this time, we still need to add an action index to represent the serial number of a user action to complete the task . Because the data is stored in an array, so we pass subscript  index to refer to specific tasks. The reference to the actual project in general will generate a unique ID as the data in the new data when identity.

 

The method of generating the action: i, Action create a function

  Redux action in the creation function simply returns an action: action to do so would make the function more easily create porting and testing.

  Redux simply result in action to create a function passed to  dispatch() the method to initiate a dispatch process.

// 创建action
function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

// dispatch
dispatch(addTodo(text))

  Or create action is bound to create a function to automatically dispatch:

  ⚠️ Note: Action to create functions can also be asynchronous non-pure function.

ii, Action code in todolist:

 

(2)Reducer:

   How Reducers specifies the application state changes in response  actions  and sent to the store, and remember that actions have just described the fact that things happen, and the application does not describe how to update the State .

   ⚠️ on designing state structure: the development of complex applications, it is inevitable there will be some reference data with each other. I suggest you as much as possible the state paradigm, there is no nesting. All the data into an object, each data ID as the primary key, each reference data by different entities or a list ID. The state thought of as a database application. For example, the actual development, while in the state in storage  and   is a better way, in order to keep the example simple herein is not so treated. todosById: { id -> todo }todos: array<id>

 

  ⚠️  Never do these operations in the reducer inside:

  • Modify the parameters passed;
  • Performing operations with side effects, such as jump API requests and routing;
  • Call impure functions, such as  Date.now() or  Math.random().

  As long as the same pass parameters, return the next state calculated to be the same. No special circumstances, no side effects, no API request, without modifying variables, simple calculation is performed. 

 

 (A): Write a reducer, to accept the old state, action (VisibilityFilters), returns a new action:

Note: i, do not modify  state. Use  Object.assign() built a copy. It can not be used as such  Object.assign(state, { visibilityFilter: action.filter }), because it will change the first value of the parameter. You must first parameter to an empty object. You can also turn on ES7 proposal object is expanded operator support, thereby using  { ...state, ...newState } the same purpose.

ii, in  default that the return old  state. When encountered an unknown action, we must return to the old  state.

 

when i, Redux first execution, state is undefined(也就是没有值,可以触发默认值语法) , at this time we can take the opportunity to set up and return to the initial state of the application.

{} from VisibilityFilters Import './actions' 

const the initialState = { 
  visibilityFilter: VisibilityFilters.SHOW_ALL, 
  Todos: [] 
} 

function todoApp (State, Action) {
   IF ( typeof State === 'undefined' ) {
     return the initialState 
  } 
  // the default value of the syntax, it was still the old syntax 
  // here temporarily to deal with any Action, 
  // return only incoming state. 
  return State 
}

ii, it can now be processed  SET_VISIBILITY_FILTER. Need to do is change in the state  visibilityFilter.

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    default:
      return state
  }
}

  Processing a plurality of action, in a plurality of Riga reducer case.

 

(B) to avoid too much case, the reducer is split into a plurality of reducers, and then combined with the function combineReducers (): 

// exposing each reducer function through export, then: 

Import combineReducers {} from 'Redux' 
Import from the reducers * AS './reducers' 

const = todoApp combineReducers (the reducers)

 

(C) Summary:

import { combineReducers } from 'redux'
import {
  ADD_TODO,
  TOGGLE_TODO,
  SET_VISIBILITY_FILTER,
  VisibilityFilters
} from './actions'
const { SHOW_ALL } = VisibilityFilters

function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}

function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: !todo.completed
          })
        }
        return todo
      })
    default:
      return state
  }
}

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

export default todoApp

 

 

(3)Store:

 Store is to action, reduce contact to the object together. Store has the following duties:

  Again it Redux apply only a single store. When you need to split the data processing logic, you should use the  reducer combination  , rather than creating multiple store.

  To create a store based on the existing reducer is very easy: in front, we use  combineReducers() multiple merged into a reducer. Now we will import it, and pass  createStore().

   createStore() The second parameter is optional, is used to set the initial state of the state. This is useful for the development of homogeneous applications, server-side state structure redux applications may be consistent with the client, the client may be received from a network server state directly for local data initialization.

import { createStore } from 'redux'
import todoApp from './reducers'
let store = createStore(todoApp)

// 第二个参数:
let store = createStore(todoApp, window.STATE_FROM_SERVER)

 

 

(4) the data stream:

  Strict way data flow architecture is the design of the core Redux . This means that all application data follow the same life cycle, which would allow applications become more predictable and easy to understand. While also encouraging for data normalization, to avoid duplication of data using multiple and independent of each other can not be referenced.

The life cycle of the application data Redux follow these four steps:

  1. transfer store.dispatch(action)

   2. Redux store incoming calls reducer function. Store  will pass two parameters  the reducer : the current state tree and action. reducer do not have the side effects of the operation

   3. The plurality of sub-root reducer reducer should be combined into a single output state tree. (With combineReducers())

   4. Redux store to save a complete state tree root reducer returned. The next state of this new tree is applied! Subscribe to all  store.subscribe(listener) listeners will be called; listeners can call in  store.getState() to get the current state.

  You can now apply the new state to update the UI. If you are using  React Redux  binding libraries of this kind, then you should call  component.setState(newState) to update.

 

 

(5) with React:

i、安装: sudo npm install --save react-redux

ii, container assembly and display assembly:

  So that the two separate: https://juejin.im/post/5a52fe32f265da3e317e008b

  difference:

 

   Most of the components should be showing type , but generally require a handful of container components and Redux store them connected. This design does not mean Introduction The following top-level container component must be in the component tree. If a container assembly becomes too complicated (e.g., it has a large number of nested components and delivering countless callback function), then introduced into another container in the component tree.

  Technically you can directly use  store.subscribe() to write vessel components. But this is not recommended because can not be used to optimize the performance React Redux brings. Therefore, not handwritten container assembly, and using React Redux the  connect() method generates , will be detailed later.

 


 

三、Todolist with react-redux:

  Goal: displays a list of todo items. After a todo item is clicked, will add a strikethrough and mark complete. We will show the user to add a todo paragraph. All display a switchable / // display only shows complete unfinished to-do in the footer.

  effect: 

 

 

 

The remaining notes recorded in the sample code.

 

 

 

 

 

 

Guess you like

Origin www.cnblogs.com/marvintang1001/p/11891348.html