Redux Essentials 학습 노트

32508 단어 Reduxtech
공식Tutorial에는 상하방향Redux Essentials과 하체방향Redux Fundamentals 두 가지가 있는데, 이 순서대로 진행하는 것을 추천합니다.

Redux Overview and Concepts


위에 도구에 대한 설명 등이 쓰여 있고, 이후에는 계속해서 개념이 쓰여 있다

Terms and Concepts


State Management


  • state: source of truth
  • state에 근거하여 선언적으로 묘사

  • actions: 사용자 입력으로 인한 이벤트에서 변경 state
  • Terminology


  • 응용 프로그램에서 발생한 이벤트 객체 표시
  • 실제 필드가 필요한 일반 JavaScript 객체

  • 반환type의 함수

  • Reducters: action, state 입력 출력 다음 action 함수로
  • state(이벤트) 기반action은 사건을 처리하는 사건 청취자라고 느끼게 한다
  • 수요는 결정적(비랜덤), type은imutable, 비동기적 처리와 부작용 제외

  • 응용 프로그램의 현재 상태를 저장하는 변수
  • state에서 생성하고 reducer 방법으로 되돌아갈 수 있음getState()

  • Dispatch: state 방법을 사용하여 store를 매개 변수로 변경action
  • 이것은 변화state의 유일한 수단이다
  • state 실행 방법은 촉발 이벤트로 간주

  • Selectorsdispatch에서 특정 값을 참조하는 함수
  • 자주 참고하는 속성이 있으면 편리(?)(복선)
  • Redux App Structure


    간단한 계수기를 구체적인 예로 응용하다
    Application Contents 섹션

    Redux Slices


    A "slice"is a collection of Redux reducer logic and actions for a single feature in your app, typically defined together in a single file. The name comes from splitting up the root Redux state object into multiple "slices"of state.
    'slice'는 같은 파일에 정의된 프로그램의 한 기능인 Reducter의 논리와 여러 actions의 집합을 가리킨다

    예제


    reduxjs/redux-essentials-counter-example 창고 보기
    src/features/counter/counterSlice.js
    import { createSlice } from '@reduxjs/toolkit';
    
    export const slice = createSlice({
      name: 'counter',
      initialState: {
        value: 0,
      },
      reducers: {
        increment: state => {
          // Redux Toolkit allows us to write "mutating" logic in reducers. It
          // doesn't actually mutate the state because it uses the immer library,
          // which detects changes to a "draft state" and produces a brand new
          // immutable state based off those changes
          state.value += 1;
        },
        decrement: state => {
          state.value -= 1;
        },
        incrementByAmount: (state, action) => {
          state.value += action.payload;
        },
      },
    });
    
    ...
    
    export default slice.reducer;
    
    src/app/store.js
    import { configureStore } from '@reduxjs/toolkit';
    import counterReducer from '../features/counter/counterSlice';
    
    export default configureStore({
      reducer: {
        counter: counterReducer,
      },
    });
    
    상기 예에서 store.state는'slice'이다
    import { configureStore } from '@reduxjs/toolkit'
    import usersReducer from '../features/users/usersSlice'
    import postsReducer from '../features/posts/postsSlice'
    import commentsReducer from '../features/comments/commentsSlice'
    
    export default configureStore({
      reducer: {
        users: usersReducer,
        posts: postsReducer,
        comments: commentsReducer
      }
    })
    
    이 예에서 counterstate.usersstate.posts는 각각 독립된'slice'이다.state.comments'slice'중 하나usersReducer의 변화를 책임지기 때문에'slice reducter'함수라고 불린다(다른 두 개에도 마찬가지)
    보태다
    API 참조createSlice를 참조하십시오.
    상기 예state.users에서 다음과 같은 함수는 configureStore와 다르지만 모두 슬라이스 대상에서 store를 구축한다.
    import { createSlice, createAction, PayloadAction } from '@reduxjs/toolkit'
    import { createStore, combineReducers } from 'redux'
    
    const incrementBy = createAction<number>('incrementBy')
    const decrementBy = createAction<number>('decrementBy')
    
    const counter = createSlice({
      name: 'counter',
      initialState: 0 as number,
      reducers: {
        increment: (state) => state + 1,
        decrement: (state) => state - 1,
        multiply: {
          reducer: (state, action: PayloadAction<number>) => state * action.payload,
          prepare: (value?: number) => ({ payload: value || 2 }), // fallback if the payload is a falsy value
        },
      },
      // "builder callback API", recommended for TypeScript users
      extraReducers: (builder) => {
        builder.addCase(incrementBy, (state, action) => {
          return state + action.payload
        })
        builder.addCase(decrementBy, (state, action) => {
          return state - action.payload
        })
      },
    })
    
    const user = createSlice({
      name: 'user',
      initialState: { name: '', age: 20 },
      reducers: {
        setUserName: (state, action) => {
          state.name = action.payload // mutate the state all you want with immer
        },
      },
      // "map object API"
      extraReducers: {
        // @ts-expect-error in TypeScript, this would need to be [counter.actions.increment.type]
        [counter.actions.increment]: (
          state,
          action /* action will be inferred as "any", as the map notation does not contain type information */
        ) => {
          state.age += 1
        },
      },
    })
    
    const reducer = combineReducers({
      counter: counter.reducer,
      user: user.reducer,
    })
    
    const store = createStore(reducer)
    
    store.dispatch(counter.actions.increment())
    // -> { counter: 1, user: {name : '', age: 21} }
    store.dispatch(counter.actions.increment())
    // -> { counter: 2, user: {name: '', age: 22} }
    store.dispatch(counter.actions.multiply(3))
    // -> { counter: 6, user: {name: '', age: 22} }
    store.dispatch(counter.actions.multiply())
    // -> { counter: 12, user: {name: '', age: 22} }
    console.log(`${counter.actions.decrement}`)
    // -> "counter/decrement"
    store.dispatch(user.actions.setUserName('eric'))
    // -> { counter: 12, user: { name: 'eric', age: 22} }
    

    Creating Slice Reducers and Actions


    'slice'의 이름(여기createStore과 그 중의 하나인reducter function(이곳"counter"에서 액션"increment"을 생성합니다.
    이 동작을 처리하는 슬라이스 Reducter function도 생성됩니다.
    import { createSlice } from '@reduxjs/toolkit'
    
    export const counterSlice = createSlice({
      name: 'counter',
      initialState: {
        value: 0
      },
      reducers: {
        increment: state => {
          // Redux Toolkit allows us to write "mutating" logic in reducers. It
          // doesn't actually mutate the state because it uses the immer library,
          // which detects changes to a "draft state" and produces a brand new
          // immutable state based off those changes
          state.value += 1
        },
        decrement: state => {
          state.value -= 1
        },
        incrementByAmount: (state, action) => {
          state.value += action.payload
        }
      }
    })
    
    export const { increment, decrement, incrementByAmount } = counterSlice.actions
    
    export default counterSlice.reducer
    

    Rules of Reducers


    reducters는 사용자 정의이지만 다음 규칙을 따라야 합니다.
  • {type: "counter/increment"}, state를 입력으로 다음action을 계산하고 그 밖의 일을 하지 않는다
  • 입력한 state 덮어쓰지 않고 복제한 것을 변경한 후 되돌아오기
  • 비동기식 프로세싱 및 부작용을 포함하는 로직 제외
  • Reducers and Immutable Updates


    결론적으로 함수statecreateSlice 함수에 Reducter function을 정의하면 간단한 표시로immutable 업데이트를 실현할 수 있다.
    왜냐하면createReducer(과createSlice는Immer
    프로그램 라이브러리로 이루어졌기 때문이다.
    원래 mutable로 해석됐던 작법에 따라 immutable update의 당의구조를 준비한 것으로 이해할 수 있다는 것이다.

    Details of createReducer function


    참조API 문서.
    이 매개 변수에 의하면
    객체
    function createSlice({
        // A name, used in action types
        name: string,
        // The initial state for the reducer
        initialState: any,
        // An object of "case reducers". Key names will be used to generate actions.
        reducers: Object<string, ReducerFunction | ReducerAndPrepareObject>
        // A "builder callback" function used to add more reducers, or
        // an additional object of "case reducers", where the keys should be other
        // action types
        extraReducers?:
        | Object<string, ReducerFunction>
        | ((builder: ActionReducerMapBuilder<State>) => void)
    })
    
    , 반환 값은
    대상
    {
        name : string,
        reducer : ReducerFunction,
        actions : Record<string, ActionCreator>,
        caseReducers: Record<string, CaseReducer>.
        getInitialState: () => State
    }
    
    .

    Async Logic with Thunks


    Detailed Explation을 읽으면 이해하기 쉬울 것 같아요.
    중간부품을 추가하면 일반createSlice(JavaScript 대상)과 비동기action(function) 두 가지를 동시에 처리할 수 있습니다.

    The React Counter Component


    React에서의 사용 방법 정보
    React가 내장된 훅actionuseState을 가지고 있는 것처럼 Redux의 제3자 라이브러리는 각자의 고유한 훅을 가지고 있다.
  • Reading Data with useEffect
  • 상기 "selector"함수(복선 회수!) 사용

  • 쓰기 가능useSelector
  • 는'selector'로서 무명 함수를 즉석에서 정의할 수 있다
  • 액션이 디스패치에 걸렸어, 스토어.state가 업데이트될 때마다'selector'가 다시 실행되고 다시 나타납니다
  • Dispatching Actions with const count = useSelector(selectCount)
  • 액션(여기useDispatchdispatch를 쓰기 위해increment
  • 이를 위해 dispatch(increment))에서 가져오기const dispatch = useDispatch()
  • Component State and Forms


    Redux store에 데이터를 포함해야 하는지 여부에 대한 판단 기준
  • 그 데이터는 응용된 다른 곳에서 사용합니까?
  • 이 데이터를 바탕으로 다른 데이터를 생성합니까?
  • 이 데이터를 여러 구성 요소를 구동하는 데 사용합니까?
  • 그 데이터는 특정한 시간에 복원해야 합니까?
  • 그 데이터를 캐시하고 싶습니까?
  • UI 구성 요소를 다시 로드한 후에도 데이터를 저장하시겠습니까?
  • 좋은 웹페이지 즐겨찾기