[react]research 6週目(2)-Redux(Flux pattern,redux-thunk,redux-toolkit)


6週目のミッションはRedux!
reduxの非同期処理方法,redux toolkitを理解した.
$ npm add redux react-redux redux-devtools-extension redux-logger
Fluxモードとは?
これはMVCモードの欠点を補うためにフェイスブック上に作成された一方向データストリームモードである.
MVCモードの問題
MVCモードは、双方向モードからのモデルおよびビューの依存性を有する.
appの規模が大きいほど,システムの複雑さが高くなり,予測不可能なコードが生成され,予測不可能なエラーが発生する可能性が高い.

Fluxモード
dispatcher、store、viewは独立したノードであり、入力と出力は完全に分離されている.

  • Action/Action Creator
    新しいデータを含める(直接データを持たずに行動することができます)type propertyで区切られた簡単なオブジェクトです.
    Actioncreatorは、新しく生成されたactionタイプと負荷をaction messageにパッケージ化し、dispatcherに渡します.

  • Dispatcher
    actionを受け取ってstoreに渡します.Dispatcherはコールバックを登録することができ、このコールバックはデータに対して複数の処理を行う.

  • Store
    storeはdispatcherにコールバック処理されたデータを格納する場所である.store内部のデータが変更された場合、検出は通知ビューを変更します.

  • View
    これはReactに相当する部分です.コントロールビューはstoreから変更したデータを取得し、すべてのサブビューにデータを割り当てます.データが入力されたviewは、画面を再レンダリングします.
  • 要するに、データ・ストリームは一方向に強制され、すべてのステータスがstoreに集中するため、変更を複数のコンポーネントに容易に渡すことができます.
    Redux
    reduxはフラックスモードを実現したライブラリである.
    データ処理はreducer(=dispatchに登録されているcallback)で行われる.
    redux-thunk
    Reduxでは非同期のミドルウェアを簡単に処理できます.
    オブジェクトを作成するのではなく、アクション作成関数を作成できます.
    $ npm install --save redux-thunk
    src/index.js
    import ReduxThunk from 'redux-thunk';
    import { createStore, applyMiddleware } from "redux";
    
    const store = createStore(reducers, applyMiddleware(thunk));
    
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.querySelector("#root")
    );
    redux toolkit
    Reduxの欠点を補うために、多くのボイラプレートが必要であり、複雑なコードを記述する必要がある.
    redux-thunkに基づいて使用しますが、redux-sagaなどの他のミドルウェアも使用できます.
    $ npm install @reduxjs/toolkit
    redux toolkit API
    configureStore
    import { configureStore } from '@reduxjs/toolkit';
    
    const store = configureStore({ reducer: rootReducer });
    基本ミドルウェアにredux-thunkを追加し、開発環境でRedux DevTools Extensionをアクティブにします.
    デフォルトではreducx devtoolを指定するにはreduceフィールドに入力する必要があります.
    createAction
    createActionは、動作をより簡潔にすることができます.
    import { createAction } from '@reduxjs/toolkit';
    
    export const addComment = createAction(ADD, saveData => saveData);
    export const deleteComment = createAction(DELETE, target => target);
    この生成関数を呼び出すときにパラメータを追加すると、自動的にペイロードフィールドに入ります.
    const comment1 = addComment(["user1","comment contents"]);
    // return ({
    //	type: ADD,
    //  payload: ["user1","comment contents"]
    // });
    createReducerredux toolkit (RTK)を使用すると、動作タイプを区別するswitch文とdefault文を省略できます.
    import { createReducer } from '@reduxjs/toolkit';
    
    export default createReducer(initicalState, {
      Add: (state, { payload: saveData }) => {
        const [userName, content] = saveData;
         const newCommentObject = {
            userName: userName,
            content: content,
            date: currentTime(),
            id: `${userName+currentTime()}`
          }
          const commentsArray = [...state, newCommentObject];
        return commentsArray;
      },
      DELETE: (state, { payload: target}) => {
        const deletedArray = state.filter(comment => comment.id !== target);
        return deletedArray;
      }
    })
    最初のパラメータinitialstateがdefault値であるため、default文は省略できます.
    createSlicecreateReducerはactionとreduceのすべてを持つ関数です.
    reduceはaction creatorとaction typeを宣言し、createSliceの減員は行動を宣言し、この行動が派遣されると、直ちに国を連れて行動を処理する.
    Actiontype、action creator、reduce機能があります.
    import { createSlice } from '@reduxjs/toolkit';
    
    export const commentReducer = createSlice({
      name: 'commentReducer',
      initialState: [],
      reducers: {
        Add: (state, { payload: saveData }) => {
          const [userName, content] = saveData;
          const newCommentObject = {
            userName: userName,
            content: content,
            date: currentTime(),
            id: `${userName+currentTime()}`
          }
          const commentsArray = [...state, newCommentObject];
          return commentsArray;
        },
        DELETE: (state, { payload: target}) => {
          const deletedArray = state.filter(comment => comment.id !== target);
          return deletedArray;
        }
      }
    });
    name属性は動作の経路を表し、initialstateは初期状態を表す.
    reducersプロパティは、createSliceに記述された関数の内容に従ってインポートされます.
    不変性管理createReducerおよびcreateReducerの関数にはimmerライブラリが含まれているため、不変性を自動的に管理できます.
    したがって、新しいstateオブジェクトを作成して返す必要はなく、stateを直接変更することができます.
    export const commentReducer = createSlice({
      name: 'commentReducer',
      initialState: [],
      reducers: {
        Add: (state, { payload: saveData }) => {
          const [userName, content] = saveData;
          const newCommentObject = {
            userName: userName,
            content: content,
            date: currentTime(),
            id: `${userName+currentTime()}`
          }
          state.push(newCommentObject);	// state에 push 사용
          return state;
        },
        DELETE: (state, { payload: target}) => {
          const deletedArray = state.filter(comment => comment.id !== target);
          return deletedArray;
        }
      }
    });
    自分で不変性管理を行い、新しいstateオブジェクトを形成します.
    scope
    reduceは基本的に関数自体を1つの範囲と見なします.
    export default function testReducer(state=initialState, action) {
      switch(action.type) {
        case A:
          let fruit='apple';
          return
        case B:
          let fruit='orange'; 
          // Parsing error: Identifier 'fruit' has already been declared.
          return;
        case C:
          let fruit='banana';
          // Parsing error: Identifier 'fruit' has already been declared.
          return;
        default:
          return state;
      }
    }
    ただし、createSliceおよびcreateReducer関数は、各actionタイプのコードブロックをscopeとして使用するので、変数をscope単位として使用することができる.
    const testReducer = createSlice({
      name: 'testReducer',
      initialState: [],
      reducers: {
        A: (state) => {
          let fruit='apple';
        },
        B: (state) => {
          let fruit='orange'; 
        },
        C: (state) => {
          let fruit='banana';
        }
      }
    })