【実戦】9. 徹底したReact状態管理とRedux機構(3) —— Jiraエンタープライズレベルプロジェクトを模倣したReact17+React Hook+TS4ベストプラクティス(18)


学習コンテンツのソース: React + React Hook + TS ベスト プラクティス - MOOC


元のチュートリアルと比較して、学習の開始時に最新バージョン (2023.03) を使用しました。

アイテム バージョン
反応&反応ダム ^18.2.0
反応ルーターと反応ルーターダム ^6.11.2
^4.24.8
@commitlint/cli および @commitlint/config-conventional ^17.4.4
eslint-config-prettier ^8.6.0
ハスキー ^8.0.3
糸くずステージ ^13.1.2
より美しい 2.8.4
jsonサーバー 0.17.2
クラコレス ^2.0.0
@クラコ/クラコ ^7.1.0
qs ^6.11.0
デイジェス ^1.11.7
反応ヘルメット ^6.1.0
@types/react-helmet ^6.1.6
反応クエリ ^6.1.0
@welldone-software/why-did-you-render ^7.0.1
@emotion/反応 & @emotion/styled ^11.10.6

具体的な構成や動作、内容は異なりますし、「落とし穴」も異なります。


1. プロジェクトの起動: プロジェクトの初期化と構成

2. React と Hook アプリケーション: プロジェクト リストを実装します。

3. TSアプリ:JSゴッドアシスト・強力タイプ

4. JWT、ユーザー認証、非同期リクエスト


5. CSS は実際には非常にシンプルです - CSS-in-JS を使用してスタイルを追加します


6. ユーザー エクスペリエンスの最適化 - 読み込みとエラー状態の処理



7. フック、ルーティング、および URL 状態の管理



8. ユーザーセレクターと項目編集機能


9. 詳細な React 状態管理と Redux メカニズム

1&2

3&4

5. redux の使用法についての概要

JavaScript アプリケーションの予測可能な状態コンテナー - JavaScript アプリケーションの予測可能な状態コンテナー

  • reduxとはreact直接関係ありませんが、vueまたは他の js/ts プロジェクトでも使用できます。
  • redux状態管理ツールよりも状態コンテナと呼ばれる方が正確です

html + js次に、通常の公式使用reduxを見てみましょう。

例/カウンターバニラ

<!DOCTYPE html>
<html>
  <head>
    <title>Redux basic example</title>
    <script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
  </head>
  <body>
    <div>
      <p>
        Clicked: <span id="value">0</span> times
        <button id="increment">+</button>
        <button id="decrement">-</button>
        <button id="incrementIfOdd">Increment if odd</button>
        <button id="incrementAsync">Increment async</button>
      </p>
    </div>
    <script>
      function counter(state, action) {
    
    
        if (typeof state === 'undefined') {
    
    
          return 0
        }

        switch (action.type) {
    
    
          case 'INCREMENT':
            return state + 1
          case 'DECREMENT':
            return state - 1
          default:
            return state
        }
      }

      var store = Redux.createStore(counter)
      var valueEl = document.getElementById('value')

      function render() {
    
    
        valueEl.innerHTML = store.getState().toString()
      }

      render()
      store.subscribe(render)

      document.getElementById('increment')
        .addEventListener('click', function () {
    
    
          store.dispatch({
    
     type: 'INCREMENT' })
        })

      document.getElementById('decrement')
        .addEventListener('click', function () {
    
    
          store.dispatch({
    
     type: 'DECREMENT' })
        })

      document.getElementById('incrementIfOdd')
        .addEventListener('click', function () {
    
    
          if (store.getState() % 2 !== 0) {
    
    
            store.dispatch({
    
     type: 'INCREMENT' })
          }
        })

      document.getElementById('incrementAsync')
        .addEventListener('click', function () {
    
    
          setTimeout(function () {
    
    
            store.dispatch({
    
     type: 'INCREMENT' })
          }, 1000)
        })
    </script>
  </body>
</html>

以前書いた use-undo と非常に似た感じでしょうか?

予測可能: 同じ入力パラメータの場合、関数の戻り値とその影響は確実です。


Redux ですべきこととしてはいけないこと

  • reduxstateですimmutable。これは置き換えることができるだけで、変更することはできません。その設計コンセプトは の設計コンセプトと一致しておりreact、すべてが更新されているかどうかを比較するために使用されますstate===state
  • reduxin はreducer純粋関数でなければなりません。ただし、これは非同期関数が使用できないという意味ではなく、非同期関数のコールバックで使用できます。dispatch

元の状態に戻すだけではなく、交換してみてはいかがでしょうか。

2 つの JavaScript オブジェクトのすべての属性がまったく同じであるかどうかを比較する唯一の方法は、詳細な比較を行うことですが、実際のアプリケーションでは、詳細な比較のコードは非常に大きく、大量のパフォーマンスを消費し、多くの比較が行われるため、効果的な解決策は、変更が発生するたびに開発者が新しいオブジェクトを返すように規定することです。


純粋関数とは何ですか?

  1. 外部環境の状態には依存せず、その入力パラメータにのみ依存します。同じ入力は常に同じ出力を返します。
  2. 副作用なし - 関数の入力値は変更されず、ネットワーク リクエスト、入出力デバイス、データの突然変異 (ミューテーション) などの目に見える副作用も生成されません。

6. 反応 Redux と HoC

コンテナコンポーネントはプレゼンテーションコンポーネントから分離されています

7. 【拡張学習】React Hook の歴史

以下はコースウェアの原文です。

フックの歴史

React チームは、当初から React のコードの再利用性に細心の注意を払ってきました。コードの再利用性に対する彼らのソリューションは、Mixin、HOC、Render Prop、そして現在まで Custom Hook を経ています。したがって、カスタム フック開発者の多くがカスタム フックの開発経験が豊富であっても、カスタム フック
どこからともなく生まれた製品ではありません。 Hook がどのように誕生し、React でどのような役割を果たしているのかを知ってくださいこの設計思想を理解していなければ、Custom Hook を深く理解することはできません。今日は一緒に学びましょう。




1.ミックスイン
var SetIntervalMixin = {
     
     
  componentWillMount: function() {
     
     
    this.intervals = [];
  },
  setInterval: function() {
     
     
    this.intervals.push(setInterval.apply(null, arguments));
  },
  componentWillUnmount: function() {
     
     
    this.intervals.forEach(clearInterval);
  }
};

var createReactClass = require('create-react-class');

var TickTock = createReactClass({
     
     
  mixins: [SetIntervalMixin], //使用mixin
  getInitialstate: function() {
     
     
    return {
     
     seconds: 0;},
  },
  componentDidMount: function() {
     
     
    this.setInterval(this.tick, 1000);//调用mixin上的方法
  }
})

アドバンテージ:

  1. コードを再利用するという目的は果たします

欠点:

  1. これは暗黙的な依存関係であり、React では暗黙的な依存関係は悪いものとみなされます。
  2. 名前の競合の問題
  3. ReactcreateClass でのみ動作し、ES6 ClassComponent はサポートしません
  4. 実際には、それを維持するのは難しいことがわかります

React 公式 Web サイトでは非推奨としてマークされており、公式の苦情はここにあります。

2.ホック

2015 年初め、React チームは、Mixin は推奨されず、全員が HOC モードを使用することを推奨すると発表しました。HOC は
コード
を再利用するために「デコレーター モード」を使用します。

function withWindowWidth(BaseComponent) {
     
     
  class DerivedClass extends ReactComponent {
     
     
    state = {
     
     
      windowWidth: window.innerwidth,
    }
    onResize = () => {
     
     
      this.setState({
     
     
        windowWidth: window.innerwidth,
      })
    }
    componentDidMount() {
     
     
      window.addEventListener(resizethisonResize)
    }
    componentWillUnmount(){
     
     
      window.removeEventListener(resizethisonResize)
    }
    render() {
     
     ...}
  }
}

ここから、コンテナのプレジデント コンポーネントとクラシック コンテナのコンポーネントの分離が始まります。
以下
は、HOC コンテナ コンポーネントとプレゼンテーション コンポーネントを分離する最も典型的なケースです - Redux での接続のコード例です。

export const createInfoScreen = (ChildComponent, fetchData, dataName) => {
     
     
  class HOComponent extends Comnonent {
     
     
    state = {
     
      counter: 0 }
    handleIncrementCounter = () => {
     
     
      this.setState({
     
      counter:this.state.counter + 1 });
    }
    componentDidMount(){
     
     
      this.props.fetchData();
    }
    render() {
     
     
      const {
     
      data={
     
     },isFetching, error } = this.props[dataName];
      if (isFetching) {
     
     
        return(
          <div>Loading</div>
        );
      }
      if (error) {
     
     
        return(
          <div>Something is wrongPlease tryagain!</div>
          ...
        )
      }
    }
  }
}

アドバンテージ

  1. クラスコンポーネントを含む任意のコンポーネントで動作可能
  2. それが提唱するコンテナコンポーネントとディスプレイコンポーネントの分離の原則、つまり懸念の分離が達成されています。

欠点がある

  1. 直感的ではない、読みにくい
  2. 名前の競合
  3. コンポーネントはレイヤーごとにネストされます
3. プロップをレンダリングする

2017 年以降、Render Prop が人気になりました。Render Prop は「プロキシ パターン」を使用してコードを再利用します

class WindowWidth extends React.Component {
     
     
  propTypes = {
     
     
    children: PropTypes.func.isRequired
  }
  state = {
     
     
    windowWidth: window.innerWidth,
  }
  onResize = () => {
     
     
    this.setState({
     
     
      windowWidth: window.innerWidth,
    })
  }
  componentDidMount() {
     
     
    window.addEventListener('resize', this.onResize);
  }
  componentWillUnmount() {
     
     
    window.removeEventListener('resize', this.onResize);
  }
  ...
 }

React Router も次の API 設計を採用しています。

<Route path = "/about" render= {
     
      (props) => <About {
     
     ...props} />}>

アドバンテージ:

  1. フレキシブル

欠点:

  1. 読みにくい、理解するのが難しい
4.フック

2018 年、React チームはコードを再利用する新しい方法である React Hook を発表しました。
その
主な変更点は、機能コンポーネントが独自の状態を保存できるようにすることです。それ以前は、機能コンポーネントは独自の状態を持つことができませんでした。
この
変更により、React コンポーネント内のロジックを通常の関数であるかのように抽象化できるようになります。
実装の原則
: クロージャ

import {
     
      useState, useEffect } from "react";
const useWindowsWidth = () => {
     
     
  const [isScreenSmall, setIsScreenSmall] = useState(false)

  let checkScreenize = () => {
     
     
    setIsScreenSmall(window.innerWidth < 600);
  };
  useEffect(()=> {
     
     
    checkscreenSize();
    window.addEventListener("resize", checkscreenSize);
    return () => window.removeEventListener("resize", checkScreenSize);
  }, []);

  return isScreenSmall
};

export default useWindowsWidth
import React from 'react'
import useWindowWidth from'./useWindowWidth.js'

const MyComponent = () => {
     
     
  const onSmallScreen = useWindowWidth;

  return (
    // Return some elements
  )
}

アドバンテージ:

  1. ロジックを抽出するのは非常に簡単です
  2. 組み合わせるのがとても簡単
  3. とても読みやすい
  4. 名前の競合の問題はありません

欠点がある

  1. フックには独自の使用制限があります。フックはコンポーネントの最上位レベルでのみ使用でき、コンポーネント内でのみ使用できます。
  2. クロージャが原則のため、稀に理解不能な問題が発生する場合がございます

8. なぜ redux-thunk が必要なのでしょうか?

reduxjs/redux-thunk: Redux 用のサンクミドルウェア

コアソースコード:

import type {
    
     Action, AnyAction } from 'redux'

import type {
    
     ThunkMiddleware } from './types'

export type {
    
    
  ThunkAction,
  ThunkDispatch,
  ThunkActionDispatch,
  ThunkMiddleware
} from './types'

/** A function that accepts a potential "extra argument" value to be injected later,
 * and returns an instance of the thunk middleware that uses that value
 */
function createThunkMiddleware<
  State = any,
  BasicAction extends Action = AnyAction,
  ExtraThunkArg = undefined
>(extraArgument?: ExtraThunkArg) {
    
    
  // Standard Redux middleware definition pattern:
  // See: https://redux.js.org/tutorials/fundamentals/part-4-store#writing-custom-middleware
  const middleware: ThunkMiddleware<State, BasicAction, ExtraThunkArg> =
    ({
     
      dispatch, getState }) =>
    next =>
    action => {
    
    
      // The thunk middleware looks for any functions that were passed to `store.dispatch`.
      // If this "action" is really a function, call it and return the result.
      if (typeof action === 'function') {
    
    
        // Inject the store's `dispatch` and `getState` methods, as well as any "extra arg"
        return action(dispatch, getState, extraArgument)
      }

      // Otherwise, pass the action down the middleware chain as usual
      return next(action)
    }
  return middleware
}

export const thunk = createThunkMiddleware()

// Export the factory function so users can create a customized version
// with whatever "extra arg" they want to inject into their thunks
export const withExtraArgument = createThunkMiddleware
  • ディスパッチを非同期操作に配置できる
  • redux-thunk またはその他のミドルウェアを使用すると、非同期操作を同期操作と同じくらいエレガントにすることができ、非同期操作とその他の操作は別々に分離されます。

一部の参考ノートはまだ草案段階にあるため、今後の内容に注目してください。

おすすめ

転載: blog.csdn.net/qq_32682301/article/details/132064487