Redux entry level tutorial documentation
Here I will explain Redux to you in plain English and teach you how to use Redux step by step.
I. Concept description
1. What is Redux and why do you use Redux
Redux is a JavaScript state container that provides predictable state management.
What does that mean? In other words, as a page becomes complicated, a lot of data on the page needs to be saved. If a route is redirected, the data on the previous page is destroyed, resulting in data loss.
Passing through a URL is cumbersome, passing every piece of data into a component is a mindless waste of time to write.
2. Why Redux
If there is a repository for data that needs to be retained throughout the project, and components can access the repository directly. The data will be consistent and clear all the time.
Second, environment building
1, install,
First we’ll create a React project with create-react app.
create-react-app redux-text
,
Install the story:
NPM install –save redux or yarn add redux
NPM install –save react-redux or yarn add react-redux
2. Brief explanation of concepts
Here are a few concepts that you should know a little bit about:
Store: We store a warehouse for the whole project. A project can only have one warehouse to store the data that needs to be saved.
State: data saved in store.
Action: The user’s actions on the page do not change the state in the store. To change the view on the page, you need to tell the state on the page that you want to change it through action. Note: this action only tells the warehouse that the data is about to change, not to change the data!
Reducer: Receives action requests and modifies state changes in the store.
3. Directory structure
Now let’s create a few folders and files that will be used in the project. Here is the directory structure:
. ├ ─ ─. Gitignore ├ ─ ─ the README. Md ├ ─ ─ the SRC │ └ ─ ─ action │ ├ ─ ─ oneAction. Js │ ├ ─ ─ twoAction. Js │ └ ─ ─ components │ └ ─ ─ Container │ ├ ─ ─ pageOne | ├ ─ ─ index. The js │ └ ─ ─ reducer │ ├ ─ ─ oneReducer. Js │ ├ ─ ─ twoReducer. Js │ ├ ─ ─ index. The js │ └ ─ ─ App. The CSS │ ├ ─ ├ ─..... ├── Node_modules ├─ Package. json ├─ publicCopy the code
3. Build data sources
Create two data sources:
SRC/reducer/oneReducer. Js and SRC/reducer/twoReducer js
const oneReducer = (
state = {
name: 'navigation navigation'.address: 'the fuzhou'
},
action
) => {
switch(action.type) {
case 'setName':
return {
...state,
name: action.payload.name
}
default:
returnstate; }}export default oneReducer;
Copy the code
The two parameters of the pure function oneReducer(state, action) represent the state and action named oneReducer in the store respectively.
State: stores all data sources and initial values under oneReducer.
Action: Perform different operations on different action. types to modify state data
Note: Redux does not change the original state each time it changes the state. Instead, it returns a new state, replacing the old state with the new state.
When action.type is setName, we first deconstruct the original state and attach a new value to name.
The same goes for tworeducer.js:
const twoReducer = (
state = {
age: 10,
},
action
) => {
switch(action.type) {
case 'setAge':
return {
...state,
age: 11,}default:
returnstate; }}export default twoReducer;
Copy the code
Finally, consolidate all the reducer
import { combineReducers } from 'redux';
import OneReducer from './oneReducer';
import TwoReducer from './twoReducer';
export default combineReducers({
OneReducer,
TwoReducer,
})
Copy the code
CombineReducers: Form all the sub-reducer functions into objects and provide a new reducer function
4. Write pages
Let’s write a simple page that presents the data from both sources.
1. Create a repository
Open the SRC/index. Js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as serviceWorker from './serviceWorker';
import PageOne from './container/pageOne';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import Reducer from './reducer';
const store = createStore(Reducer);
ReactDOM.render(
<Provider store={store}>
<PageOne/>
</Provider>
, document.getElementById('root'));
serviceWorker.unregister();
Copy the code
CreateStore: Creates a repository for all data sources under recuder.
Provider: A component provided by Redux that passes stores to its own components. Simply put, wrap a component in the outermost layer of the project and put it into a store, which binds the store into the project.
2. Display page
So now let’s focus on page/SRC/container/pageOne/index. The js code:
import React from 'react';
import { connect } from 'react-redux';
class PageOne extends React.Component {
render() {
const { oneReducer, twoReducer } = this.props;
const { name = ' ', address = ' ' } = oneReducer;
const { age = 0 } = twoReducer;
console.log(oneReducer, twoReducer);
return (
<div>
<div>name: {name}</div>
<div>address: {address}</div>
<div>age: {age}</div>
</div>)}}const mapStateToProps = state= > {
const { oneReducer, twoReducer } = state;
return {
oneReducer,
twoReducer,
}
}
export default connect(mapStateToProps)(PageOne);
Copy the code
Explain in detail the following above knowledge point ha:
MapStateToProps: Get the data source under the Store repository. Here you can print the following state to see the output.
Connect: method provided by the React Redux library that maps the current Redux store state to the presentation component props.
Connect has been optimized to avoid many unnecessary repeated renders, such as writing a shouldComponentUpdate method to update the presentation data when state data changes.
So, at this point, we can get the data in the warehouse using this.props.
3. Modify warehouse data
Store data cannot be modified, which ensures data stability. So redux throws a store.dispatch(Action) event that allows the user to modify store data.
So we continue to modify the pageOne/index.js page above (short) :
class PageOne extends React.Component {
changeName = (val) = > {
this.props.dispatch({
type: 'setName'.payload: {
name: val
}
})
}
render() {
return (
<div>
<div>name: {name}</div>
<div>address: {address}</div>
<div>age: {age}</div>
<button onClick={() = >{this.changename ('change_name')}}> Change the name</button>
</div>)}}Copy the code
Now try the following execution button click events.
Ok, so at this point a state management operation is complete. If you are careful, you will notice that action is not used.
So what exactly does this action do?
In my understanding, that means putting the contents of the dispatch into the action.
Write actions
Write the SRC/action/oneAction. Js
export const setName = (name) = > ({
type: 'setName'.payload: {
name,
}
})
export const setAge = (age) = > ({
type: 'setAge',
age
})
Copy the code
Modify pageOne/index.js (short) :
import { setName } from '.. /.. /action/oneAction';
class PageOne extends React.Component {
changeName = (val) = > {
this.props.dispatch(setName(val))
}
...
}
Copy the code
Does the following work for discovery? So why do we write actions?
In my understanding: In order to pay more attention to MVC mode, View should pay more attention to the display logic of View, so the logic operation unrelated to UI is entrusted to Redux to deal with, reflecting the programming idea of code stratification and responsibility separation.
Middleware – Asynchronous
1. Code operation (the second point is the knowledge point explanation, small friends want to see ha)
Since in most cases, dispatch is not just to update reducer immediately, other functions need to be executed to meet the needs of the project, such functions are middleware. Finally, reducer is executed after a series of middleware
If we call the server interface, there is a time delay; Or I want to take other reducer operations from the Reducer as well, ok?
Let’s try it out:
Add another method to our oneaction.js file:
export const allChange = (a)= > dispatch => {
dispatch(setName('all_hang'));
dispatch(setAge(10010));
}
Copy the code
Add a click event (short) to pageone. js:
import { setName, allChange } from '.. /.. /action/oneAction'; class PageOne extends React.Component { changeAll = () => { this.props.dispatch(allChange()) } render() { return ( ... The < div > < button onClick = {() = > {enclosing changeAll ()}} > modify all < / button > < / div >...). }}Copy the code
We found the error when we clicked the button. Use custom middleware for async Actions. Use custom middleware for asynchronous operations.
It is ok to call other reducer methods from reducer, but because we lack middleware, we received an error. Now let’s add the middleware:
Before we modify the code we need to edit the CLI and add a new command
Yarn add redux-thunk or NPM install –save redux-thunk Import the redux-thunk library.
Edit SRC /index.js(short):
The following is shorthand code. The original content on the page is not removed, but a few lines of code have been added and the createStore has been modified
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
conststore = createStore( Reducer, applyMiddleware( thunkMiddleware ) ); . .Copy the code
Now execute the following allChange() event to see if the page does not report an error and the name and age data have been changed.
2. Knowledge points
So let’s talk about applyMiddleware and thunkMiddleware
What is Middleware:
In Redux, middleware is a third-party extension between actions sent and actions delivered to the reducer, and middleware is a bridge between actions and stores.
See the explanation on applyMiddleware’s website.
Middleware lets you wrap a store’s dispatch() method to do what you want.
3, add
One final addition:
If you want to be able to print logs on the console every time you dispatch, hand-writing can be tedious.
Redux also provides such middleware to help us print logs.
Type YARN Add redux-Logger or NPM install –save redux-Logger to import the redux-Logger library.
Add the following code to SRC /index.js:
import { createLogger } from 'redux-logger'
const loggerMiddleware = createLogger()
const store = createStore(
Reducer,
applyMiddleware(
thunkMiddleware,
loggerMiddleware
)
);
Copy the code
Well, go for it