preface
Ask the question, why redux? What problem does it solve?
The React website saysA JavaScript library for building user interfaces
“, which means JavaScript libraries that focus on building user interfaces. Is used to bringstate / props
The data,JSX
Convert the code to a real HTML page. React, like vue.js, does not manage global state (data). React transfers data from parent to child components from top to bottom.
In the project, we often have such a requirement, according to the current login user information display different menus or data, this requires that we can obtain the login user information in any component, how to do? Without these frameworks, we would certainly find a way to store the global information in a unified place, design the corresponding data structure exists in a JS object, and this object mustThe singletonEnsure that the data obtained each time is the same. For modification logic, there are also established rules to be followed to ensure that every data modification is traceable. Without the conventions of these rules, state (data) changes become chaotic, code becomes chaotic, and potential problems with the system multiply.
Redux has emerged for managing state (data) in projects. And Redux tries to make state changes predictable. Let’s go down.
redux
The figure above shows the flow of REdux data. The React component or other components passstore.getState()
从 Store
To retrieve data. You can modify data only through thestore.dispatch(action)
向 Store
Submit instructions to modify data,Store
Data modification is handled uniformly.Reducers
Is the corresponding logical handler function that takes two arguments(previousState, action)
The action directive, representing the value of the previous state state and the action directive, returns a new data newState. Pay attention toReducers
Is a pure function that does not modify the received data directly, but returns a new data newState; At the same time, once(previousState, action)
Sure, the result is the same multiple times. The whole process is redux’s three principles:
-
Single data source: Data in a store is singleton and globally unique.
-
State is read-only: the only way to change State is to trigger action, store.dispatch(action); Modifying state directly does not work.
-
Reducers are pure functions that ensure that the results of repeated implementation are the same under the premise of (previousState, Action) determination; Instead of directly modifying the state, the Store triggers the change of state.
In addition, redux has three important functions:
// Initialize the store
const store = createStore(reducers);
/ / for the state
store.getState();
// Trigger action to request data modification
store.dispatch(action);
// The subscription data changes callback function
store.subscribe(() = >{
//to do
});
Copy the code
Redux is easy to use
Instead of using React or Vue, we’ll simply use redux as an example. Build a small project using Webpack and add NPM install redux -d to the project. The directory structure is as follows:
├─ ├─ SRC │ index.html │ ├─ ├─build │ ├.dev.config.js // ├─ SRC │ index.html │ // ├─build │ ├.dev.config.js // ├─ SRC │ index.html │ ├─ Actions │ actionCreator. Js // Action Creator; ├─ ├─ ├─ ├─ download.txt // download.txt // download.txt // download.txtCopy the code
In the index.js entry file, we initialize the store data, bind the button to events, and send the action to the store via store.dispatch(addCounter(1)).
//index.js
import store from './store';
import {addCounter} from './actions/actionCreator';
/ / initialization
const stateData = store.getState();
document.getElementById("counter").innerHTML = stateData.counter;
document.getElementById("otherUsed").innerHTML = stateData.counter;
document.getElementById("myBtn").addEventListener("click".() = >{
/ / triggers
store.dispatch(addCounter(1));
})
/ / subscribe
store.subscribe(() = >{
const stateData = store.getState();
document.getElementById("counter").innerHTML = stateData.counter;
document.getElementById("otherUsed").innerHTML = stateData.counter;
})
Copy the code
The task is to process the data logic according to the type of the action:
// reducers/index.js
const defaultState = {
counter: 10
}
export default (state = defaultState, action)=>{
if(action.type==="add") {const newState = JSON.parse(JSON.stringify(state));
newState.counter = newState.counter + action.value;
return newState;
}
return state;
}
Copy the code
This example shows that Redux and React are not strongly coupled and can be used independently. Source code address: github.com/YY88Xu/redu…
React + Redux (todoList)
Create react-app initializes the project with the following directory structure:
Todo-list │ package.json │ package.json │ ├─ Public │ Favicon. Ico │ index.html │ logo192 Logo512. PNG │ │ manifest. Json │ │ robots. TXT │ │ │ └ ─ API │ initList. Json │ └ ─ SRC │ App. CSS │ App. Js │ App. Test, js │ │ ├─ Common │ Actiontypes.js │ ├─ Reacts-redux // Reacts-redux │ ├─ Actions │ actionCreator. Js │ │ ├─ Components │ │ Todolist.js │ │ ├─reducers │ index.js │ │ ├─ Reacts-Redux │ ├─ Actions │ actionCreator └ ─ store │ index. Js │ ├ ─ redux / / redux │ ├ ─ actions │ │ actionCreator. Js │ │ │ ├ ─ components │ │ TodoList. Js │ │ │ ├ ─ reducers │ │ index. Js │ │ │ └ ─ store │ index. The js │ ├ ─ redux - saga / / story - saga implementation │ ├ ─ actions │ │ actionCreator. Js │ │ │ ├ ─ components │ │ TodoList. Js │ │ │ ├ ─ reducers │ │ index. The js │ │ │ ├ ─ saga │ │ index. The js │ │ │ └ ─ store │ index. The js │ ├─ ├─ ├─ exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises └ ─ store index. JsCopy the code
actions
A function that returns an action object, usually with a type attribute. Responsible for the generation of instructions, the page through store.dispatch(action) to send data modification requests to the store.
reducers
A pure function that takes two arguments (previousState, action), the first of which represents the value of the previousState. Action is the action passed from the previous page to the store via store.dispatch(action). Reducers handles the action’s type value differently, returning a new variable, newState. Reducers cannot directly modify the previousState passed in.
store
Pass const store = createStore(Reducer); Create a Store object.
To import the React component file, run this.state = store.getState(); Let the component get the data in the store;
And subscribe to changes in the store data in the componentDidMount lifecycle function:
componentDidMount(){
store.subscribe(() = >{
this.setState(store.getState());
});
}
Copy the code
react-redux
Redux redux redux redux redux redux redux redux
npm install react-redux -D
Copy the code
<Provider>
Component, which simplifies the process of importing the React component file store each time.
import { Provider } from "react-redux";
<Provider store={store}>/ / store inside<TodoList/>
</Provider>
Copy the code
mapStateToProps
Function to storestate
component-to-componentprops
mapDispatchToProps
Function, passed indispatch
Used to trigger an action.connect
Function.
const mapStateToProps = (state) = >({
inputValue: state.inputValue,
list: state.list
})
const mapDispatchToProps = (dispatch) = > ({
hanldeAdd: () = >{
dispatch(addItem());
},
changeInputValue: (e) = >{
dispatch(changeValue(e.target.value));
},
deleteItem: (key) = >{
dispatch(deleteItem(key))
}
})
MapStateToProps and mapDispatchToProps
// And returns a function that accepts TodoList to return a wrapped component.
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
Copy the code
asynchronous
Two middleware that handle asynchronous Redux, Redux-Thunk and Redux-Saga.
Or a question? What does middleware mean between where and where? The answer is: “play some tricks” between Actions and reducers, processing asynchronous requests before triggering dispatch to initiate operations to the Store.
Without this middleware, we could have implemented the business requirements. Using these middleware is a way to strip asynchronous logic away, with cleaner code and higher maintainability.
redux-thunk
Use with Redux enhances redux’s capabilities. Before actions return an object, asynchronous actions can return a function:
// actionCreator.js
export const getInitList = () = > {
return function(dispatch){
axios.get("/api/initList.json").then(res= >{
dispatch(initList(res.data))
})
}
}
Copy the code
Redux-thunk creates a store
import { createStore, applyMiddleware } from "redux";
import thunk from 'redux-thunk';
import reducer from '.. /reducers';
const store = createStore(reducer, applyMiddleware(thunk));
export default store;
Copy the code
See the code in the project’s redux-Thunk folder for details.
redux-saga
Redux-saga is also a middleware component of Redux that handles asynchronous actions. TakeEvery (GET_INIT_LIST, getInitList) to listen for action.type is the GET_INIT_LIST action that executes the getInitList method to get asynchronous data.
// saga/index.js
import {takeEvery, put} from 'redux-saga/effects';
import { GET_INIT_LIST } from ".. /.. /common/actionTypes.js";
import { initList} from ".. /actions/actionCreator.js";
import axios from 'axios';
function* getInitList(){
try{
const res = yield axios.get("/api/initList.json");
const action = initList(res.data);
yield put(action);
}catch(e){
console.log("Initlist. json network request failed")}}function* mySaga(){
yield takeEvery(GET_INIT_LIST, getInitList);
}
export default mySaga;
Copy the code
See the code in the project’s Redux-Saga folder for details.
The source code
Address: github.com/YY88Xu/todo…
The last
If there is any mistake or not precise place, please give correction, thank you very much. If you like or have some inspiration, welcome to like, to the author is also a kind of encouragement.