Use of redux
JavaScript pure function
In functional programming, there is a concept called pure function. JavaScript conforms to the paradigm of functional programming, so there is also the concept of pure function;
Wikipedia definition of pure functions:
In programming, a function is called a pure function if it meets the following conditions:
- This function needs to produce the same output when it has the same input value. The output of the function has nothing to do with the hidden information or state other than the input value, and has nothing to do with the external output generated by the I/O device.
- This function cannot have semantically observable function side effects, such as "trigger event", make the output device output, or change the contents of objects other than the output value.
Of course, the above definition will be too obscure, so let me briefly summarize:
- Certain input will produce certain output;
- The function cannot produce side effects during execution;
Case 1:
Obviously, the following function is a pure function; Its output depends on our input content, and there is no side effect in the middle;
Case 2:
The add function is not a pure function; The function depends on an external variable. When the variable changes, it will affect: the determined input will produce the determined output; Can it be improved into a pure function? const foo = 5; that will do
Pure function in React
Why are pure functions so important in functional programming?
- Because you can write and use at ease;
- When you write, you ensure the purity of the function, but only implement your own business logic. You don't need to care about the incoming content or rely on other external variables;
- When you use it, you make sure that your input content will not be tampered with arbitrarily, and the input you determine will have a certain output;
In React, we are required to declare a component whether it is a function or a class. This component must be like a pure function to protect their props from being modified. In redux, reducer is also required to be a pure function.
Why do I need redux
Applications developed with JavaScript have become more and more complex:
- JavaScript needs to manage more and more complex states;
- These statuses include the data returned by the server, cached data, data generated by user operations, etc., as well as some UI statuses, such as whether some elements are selected, whether the loading dynamic effect is displayed, and the current paging;
Managing changing state s is very difficult:
- There will be interdependence between states. The change of one state will cause the change of another state, and the View page may also cause the change of state;
- When the application is complex, when, why and how the state changes will become very difficult to control and track;
React helps us solve the DOM rendering process in the view layer, but the State is still left to us to manage:
- Whether the component defines its own state or the communication between components is transmitted through props; It also includes data sharing through Context;
- React is mainly responsible for helping us manage the view. How to maintain the state is ultimately up to us;
Redux is a container that helps us manage states: Redux is a JavaScript State container that provides predictable State management; In addition to using with React, Redux can also be used with other interface libraries (such as Vue), and it is very small (including dependencies, only 2kb)
Redux - Store/action/reducer
The core concept of Redux is very simple.
For example, we have a list of friends to manage:
- If we do not define a unified specification to operate this data, the change of the whole data cannot be tracked;
- For example, somewhere on the page through products The push method adds a piece of data;
- For example, another page through products [0] Age = 25 modifies a piece of data;
The whole application is complex. When there is a bug, it is difficult to track where the change takes place;
Redux requires us to update data through action:
- All data changes must be updated through dispatch action;
- action is a common JavaScript object used to describe the type and content of this update;
For example, here are some action s to update friends:
The advantage of mandatory use of action is that you can clearly know what changes have taken place in the data, and all data changes are traceable and predictable; Of course, at present, our action is a fixed object. In real applications, we will define it through functions and return an action;
But how do you associate state with action? The answer is reducer, which is a pure function; What reducer does is to combine the incoming state and action to generate a new state;
Three principles of Redux
Single data source
- The state of the entire application is stored in an object tree, and the object tree is only stored in one store:
- Redux does not force us to create multiple stores, but that is not conducive to data maintenance;
- A single data source can make the state of the whole application easy to maintain, track and modify;
State is read-only
- The only way to modify the State must be to trigger action. Do not try to modify the State in any other way:
- This ensures that neither the View nor the network request can directly modify the state. They can only describe how they want to modify the state through action;
- In this way, all modifications can be centralized and executed in strict order, so there is no need to worry about race condition;
Use pure functions to perform modifications
- Connect the old state and actions through reducer, and return a new state:
- As the complexity of the application increases, we can split the reducer into several small reducers to operate part of different state tree s respectively;
- However, all reducer s should be pure functions without any side effects;
Use of Redux
To install redux:
npm install redux --save or yarn add redux
1. Create a new project folder: XXX
- Perform initialization operation yarn init
- Install redux yarn add redux
2. Create src directory and index JS file
3. Modify package JSON can execute index js
"scripts": {
"start": "node src/index.js"
}
Use process of Redux
1. Create an object as the state we want to save:
2. Create a Store to Store this state
- When creating a store, you must create a reducer;
- We can use store Getstate to get the current state
3. Modify state through action
- Dispatch action s through dispatch;
- Usually, the action will have the type attribute, and other data can also be carried;
4. Modify the processing code in reducer
- It must be remembered here that reducer is a pure function, and there is no need to modify the state directly;
- Later, I will talk about the problems caused by directly modifying state;
5. You can monitor the changes of the store before sending the action
view code// 1. Import Redux (not through ES6) // import/export 13.2.0 is supported // An implementation of commonjs - > nodejs const redux = require('redux'); const initialState = { counter: 0 } // reducer function reducer(state = initialState, action) { switch (action.type) { case "INCREMENT": return { ...state, counter: state.counter + 1 } case "DECREMENT": return { ...state, counter: state.counter - 1 } case "ADD_NUMBER": return { ...state, counter: state.counter + action.num } case "SUB_NUMBER": return { ...state, counter: state.counter - action.num } default: return state; } } // Store (a reducer needs to be passed in when creating) const store = redux.createStore(reducer) // Modification of subscription store store.subscribe(() => { console.log("counter:", store.getState().counter); }) // actions const action1 = { type: "INCREMENT" }; const action2 = { type: "DECREMENT" }; const action3 = { type: "ADD_NUMBER", num: 5 }; const action4 = { type: "SUB_NUMBER", num: 12 }; // Dispatch action store.dispatch(action1); store.dispatch(action2); store.dispatch(action2); store.dispatch(action3); store.dispatch(action4);
Redux structure division
If we put all the logic code together, the code will be difficult to maintain when redux becomes complex.
p next, I'll split the code and split the store, reducer, action and constants into files.
- Create store / index JS file:
- Create store / reducer JS file:
- Create store / actioncreators JS file:
- Create store / constants JS file:
view code//index.js import redux from 'redux'; import reducer from './reducer.js'; const store = redux.createStore(reducer); export default store;
view code//reducer.js import { ADD_NUMBER, SUB_NUMBER, INCREMENT, DECREMENT } from './constants.js'; const defaultState = { counter: 0 } function reducer(state = defaultState, action) { switch (action.type) { case ADD_NUMBER: return { ...state, counter: state.counter + action.num }; case SUB_NUMBER: return { ...state, counter: state.counter - action.num }; case INCREMENT: return { ...state, counter: state.counter + 1 }; case DECREMENT: return { ...state, counter: state.counter - 1 }; default: return state; } } export default reducer;
view code//constants.js export const ADD_NUMBER = "ADD_NUMBER"; export const SUB_NUMBER = "SUB_NUMBER"; export const INCREMENT = "INCREMENT"; export const DECREMENT = "DECREMENT";
import { ADD_NUMBER, SUB_NUMBER, INCREMENT, DECREMENT } from './constants.js'; // export function addAction(num) { // return { // type: "ADD_NUMBER", // num // } // } // export const addAction = (num) => { // return { // type: "ADD_NUMBER", // num // } // } export const addAction = num => ({ type: ADD_NUMBER, num }); export const subAction = num => ({ type: SUB_NUMBER, num }); export const incAction = () => ({ type: INCREMENT }); export const decAction = () => ({ type: DECREMENT });
Note: node supports ES6 modularization
- At present, the node version I use is V12 16.1, from node V13 Since 2.0, node has provided support for ES6 Modularization: node V13 Before 2.0, the following operations are required:
- In package Add attribute: "type": "module" in JSON;
- Add the following options in the command: node -- experimental modules Src / index js;
- node v13. After 2.0, only the following operations are required:
- In package Add attribute: "type": "module" in JSON;
Note: you need to keep up when importing files js suffix;