Web study notes-React (Redux)

The content of the notes is reproduced from AcWing's Web Application Course handout, course link: AcWing Web Application Course .

We mentioned a problem before, that is, if two sibling components want to access each other's data, they need to store the data in the nearest common ancestor, which is very troublesome when the DOM tree is complex. Redux is a place outside the entire DOM tree to store some global values.

1. Basic concepts of Redux

Redux will statemaintain it as a tree structure, each node stores a value, and uses a function reducerto maintain each value. Redux uses dictionaries to store child nodes, generally called store.

If we want to modify a certain value in the tree, the entire tree will be recalculated. We'll use dispatcha function, which will call each function recursively reducer. In addition, an object parameter needs to be passed in to indicate which node needs to be operated. There is an attribute in it type, and we will define a unique one for each node type.

The basic concepts of Redux are summarized as follows:

  • store:Storage tree structure.
  • state: The data maintained is generally maintained in a tree structure.
  • reducer: stateFunction to update, one stateis bound to each reducer. Pass in two parameters: current stateand action, return new state.
  • action: A common object that stores reducerthe incoming parameters of and generally describes statethe update type of , where typethe attribute represents the node to be modified.
  • dispatch: Pass in a parameter actionand stateoperate the entire tree once, that is, recursively call all reducerfunctions of the entire tree.

Let's first create a Redux project redux-app:

create-react-app redux-app

Enter the project root directory and install the relevant modules:

npm i redux react-redux @reduxjs/toolkit

Assuming that we only maintain one now state, we build the simplest plain version of Redux (nothing to do with React):

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import {
    
     configureStore } from '@reduxjs/toolkit';

const f1 = (state = 0, action) => {
    
      // reducer函数
  switch(action.type) {
    
    
    case 'add':
      return state + action.val;
    case 'sub':
      return state - action.val;
    default:
      return state;
  }
};

const store = configureStore({
    
      // 将f1函数构建成一棵状态树
  reducer: f1
});

store.subscribe(() => {
    
    console.log(store.getState())});  // 每次dispatch完之后会执行一遍该函数

store.dispatch({
    
    type: 'add', val: 2});  // 修改state
store.dispatch({
    
    type: 'add', val: 3});

console.log(store.getState());  // 返回整棵树的值

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
  </React.StrictMode>
);

Now let's see how to maintain two nodes:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import {
    
     configureStore } from '@reduxjs/toolkit';

const f1 = (state = 0, action) => {
    
      // reducer函数
  switch(action.type) {
    
    
    case 'add':
      return state + action.val;
    case 'sub':
      return state - action.val;
    default:
      return state;
  }
};

const f2 = (state = '', action) => {
    
    
  switch(action.type) {
    
    
    case 'concat':
      return state + action.character;
    default:
      return state;
  }
};

const f_all = (state = {
     
     }, action) => {
    
      // 组合了f1与f2
  return {
    
    
    f1: f1(state.f1, action),
    f2: f2(state.f2, action),
  }
};

const store = configureStore({
    
      // 将f_all函数构建成一棵状态树
  reducer: f_all
});

store.subscribe(() => {
    
    console.log(store.getState())});  // 每次dispatch完之后会执行一遍该函数

store.dispatch({
    
    type: 'add', val: 2});  // 修改f1的state
store.dispatch({
    
    type: 'add', val: 3});
store.dispatch({
    
    type: 'concat', character: 'abc'});  // 修改f2的state

console.log(store.getState());  // 返回整棵树的值

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
  </React.StrictMode>
);

The console output is as follows:

{f1: 2, f2: ''}
{f1: 5, f2: ''}
{f1: 5, f2: 'abc'}
{f1: 5, f2: 'abc'}

f_allYou don’t need to write it yourself, you can use combineReducers:

import {
    
     combineReducers } from '@reduxjs/toolkit';

const f_all = combineReducers({
    
    
  f1: f1,
  f2: f2,
});

2. Basic concepts of React-Redux

Now let's take a look at how Redux is combined with React. We need to Providerwrap up our entire project with . The basic concepts of React-Redux are as follows:

  • ProviderComponent: Used to wrap the entire project, and its storeproperties are used to store Redux storeobjects.
  • connect(mapStateToProps, mapDispatchToProps)Function: used to storeassociate with a component. This function will return a function. The returned function can take the component as an input parameter and then return a new component. This new component will bind the statevalue of to the component's propsproperty.
    • mapStateToProps: storeCalled once every time the status in is updated to update the value in the component, that is, the value storein stateis bound to the component's propsattribute.
    • mapDispatchToProps: Called once when the component is created, it is used to pass the function storeof dispatchthe component into the component, that is, dispatchto map the function to the component's propsattribute.

For the convenience of display, we define three components: App, Number( statestarting from 0), String( statestarting from the empty string).

Appcode show as below:

import React, {
    
     Component } from 'react';
import Number from './number';
import String from './string';

class App extends Component {
    
    
    state = {
    
      }
    render() {
    
    
        return (
            <React.Fragment>
                <Number />
                <hr />
                <String />
            </React.Fragment>
        );
    }
}

export default App;

Then we index.jsimplement React-Redux in:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import {
    
     configureStore } from '@reduxjs/toolkit';
import {
    
     combineReducers } from '@reduxjs/toolkit';
import {
    
     Provider } from 'react-redux';
import App from './components/app';

const f1 = (state = 0, action) => {
    
      // reducer函数
  switch(action.type) {
    
    
    case 'add':
      return state + action.val;
    case 'sub':
      return state - action.val;
    default:
      return state;
  }
};

const f2 = (state = '', action) => {
    
    
  switch(action.type) {
    
    
    case 'concat':
      return state + action.character;
    default:
      return state;
  }
};

const f_all = combineReducers({
    
    
  number: f1,
  string: f2,
});

const store = configureStore({
    
      // 将f_all函数构建成一棵状态树
  reducer: f_all
});

store.subscribe(() => {
    
    console.log(store.getState())});  // 每次dispatch完之后会执行一遍该函数

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={
    
    store}>
    <App />
  </Provider>
);

Now let's take a look at how to call their values ​​in Numberand components . We need to use an API: , taking as an example :StringstateconnectNumber

import React, {
    
     Component } from 'react';
import {
    
     connect } from 'react-redux';

class Number extends Component {
    
    
    state = {
    
      }
    render() {
    
    
        console.log(this.props);
        return (
            <React.Fragment>
                <h3>Number: {
    
    this.props.number}</h3>
            </React.Fragment>
        );
    }
};

const mapStateToProps = (state, props) => {
    
      // 第一个参数state包含整个状态树的树结构
    return {
    
    
        number: state.number,
    }
};

export default connect(mapStateToProps)(Number);

Now let's take a look at how to modify statethe value of . We need to define mapDispatchToPropsan object to dispatchmap to props. Suppose we want Numberto operate Stringin state:

import React, {
    
     Component } from 'react';
import {
    
     connect } from 'react-redux';

class Number extends Component {
    
    
    state = {
    
      }

    handleClick = () => {
    
    
        this.props.concat('abc');
    }

    render() {
    
    
        console.log(this.props);
        return (
            <React.Fragment>
                <h3>Number: {
    
    this.props.number}</h3>
                <button onClick={
    
    this.handleClick}>添加</button>
            </React.Fragment>
        );
    }
};

const mapStateToProps = (state, props) => {
    
      // 第一个参数state包含整个状态树的树结构
    return {
    
    
        number: state.number,
    }
};

const mapDispatchToProps = {
    
    
    concat: (character) => {
    
    
        return {
    
      // 会返回一个对象,这个对象就是dispatch中用到的action,会将返回值作用到整个状态树中
            type: 'concat',
            character: character,
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(Number);

Guess you like

Origin blog.csdn.net/m0_51755720/article/details/132795163