Web勉強メモ - React (Redux)

メモの内容は、AcWing の Web アプリケーション コースの配布資料 (コース リンク: AcWing Web アプリケーション コース )から転載されています。

前に問題について触れました。つまり、2 つの兄弟コンポーネントが互いのデータにアクセスしたい場合、最も近い共通の祖先にデータを保存する必要がありますが、DOM ツリーが複雑な場合、これは非常に面倒です。Redux は、一部のグローバル値を保存するための DOM ツリー全体の外側の場所です。

1. Reduxの基本概念

Redux はstateそれをツリー構造として維持し、各ノードが値を保存し、関数を使用してreducer各値を維持します。Redux は辞書を使用して、一般に と呼ばれる子ノードを保存しますstore

ツリー内の特定の値を変更する場合は、ツリー全体が再計算されます。dispatch各関数を再帰的に呼び出す関数を使用しますreducerさらに、どのノードを操作する必要があるかを示すオブジェクト パラメータを渡す必要があります。その中には属性があり、typeノードごとに一意の属性を定義しますtype

Redux の基本概念は次のように要約されます。

  • store:ストレージツリー構造。
  • state: 保持されるデータは通常、ツリー構造で保持されます。
  • reducer:state更新する関数。state各 に 1 つバインドされますreducer2 つのパラメータ currentstateとを渡しaction、 new を返しますstate
  • actionreducer:の受信パラメータを格納し、一般に のstate更新タイプを記述する共通オブジェクト。type属性は変更されるノードを表します。
  • dispatch: パラメータを渡してツリー全体を一度操作actionstateます。つまり、reducerツリー全体のすべての関数を再帰的に呼び出します。

まず Redux プロジェクトを作成しましょうredux-app

create-react-app redux-app

プロジェクトのルート ディレクトリを入力し、関連モジュールをインストールします。

npm i redux react-redux @reduxjs/toolkit

現在は 1 つだけを維持していると仮定してstate、最も単純なプレーン バージョンの Redux (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>
);

次に、2 つのノードを維持する方法を見てみましょう。

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>
);

コンソール出力は次のとおりです。

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

f_all自分で記述する必要はなく、以下を使用できますcombineReducers

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

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

2. React-Redux の基本概念

次に、Redux と React がどのように組み合わされるかを見てみましょう。Providerプロジェクト全体を で終える必要があります。React-Redux の基本概念は次のとおりです。

  • Providerコンポーネント: プロジェクト全体をラップするために使用され、そのstoreプロパティは Reduxstoreオブジェクトを保存するために使用されます。
  • connect(mapStateToProps, mapDispatchToProps)関数:storeコンポーネントとの関連付けに使用されます。この関数は関数を返します。返された関数はコンポーネントを入力パラメータとして受け取り、新しいコンポーネントを返すことができます。この新しいコンポーネントは、 の値をコンポーネントのプロパティにバインドしstateますprops
    • mapStateToProps:storeのステータスが更新されるたびに 1 回呼び出され、コンポーネントの値が更新されます。つまり、の値storestateコンポーネントのprops属性にバインドされます。
    • mapDispatchToPropsstore: コンポーネントの作成時に 1 回呼び出され、コンポーネントの関数をコンポーネントに渡すために使用されますdispatch。つまり、dispatch関数をコンポーネントのprops属性にマップします。

表示の便宜上、AppNumber( state0 から始まる)、String(state空の文字列から始まる) の 3 つのコンポーネントを定義します。

Appコードは以下のように表示されます。

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;

次に、index.jsReact-Redux を以下に実装します。

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>
);

Number次に、とコンポーネント の値をString呼び出す方法を見てみましょうstate。 API: を使用する必要がありますconnectNumber例。

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);

state次に、の値を変更する方法を見てみましょう。にマップするmapDispatchToPropsオブジェクトを定義する必要があります。操作したいとしますdispatchpropsNumberStringstate

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);

おすすめ

転載: blog.csdn.net/m0_51755720/article/details/132795163