12줄 코드에서 vanilla React를 사용하여 Redux 재설정

28275 단어 reactjavascript
Redux는 반응이 있든 없든 대형 응용 프로그램의 상태를 처리할 수 있는 훌륭한 라이브러리입니다.하지만 레드ux의 기본 기능은 몇 줄의 코드만으로도 가능하다.어떠신지 한번 봅시다.
면책 성명: 이 글은 글로벌 상태 관리 시스템을 실현하는 것이 아니라 감축기와 상하문의 개념을 더 잘 이해하는 데 쓰여야 한다.저자 참조
.
this post
언어 환경
React에서 상하문은'공급자/소비자'모델을 실현하는 우아한 방식을 제공했다.말하자면 이런 모델은 두 가지 주요 요소로 구성된다. 하나는 공급자이고 그 목표는 특정한 가치를 제공하는 것이다. 다른 하나는 소비자가 이 가치를 소비할 구성 요소이다.일반적으로 마스터 어셈블리를 Provider 어셈블리에 패키지한 다음 서브어셈블리에서 위아래 라이브러리에서 제공하는 연결을 사용합니다.
// Main component:
return (
  <Provider params={someParams}>
    <App />
  </Provider>
)

// In App or a child component:
const value = useValueFromProvider()
위아래 문장을 만들기 위해서, 우리는 React에서 제공하는 createContext 함수를 호출합니다.되돌아오는 대상은 Provider 구성 요소를 포함합니다.이 구성 요소에서 구성 요소의 차원 구조를 봉인하면 위아래 문장의 값에 접근할 수 있습니다.
const myContext = createContext()

const App = () => (
  <myContext.Provider value="Hello">
    <SomeComponent />
  </myContext.Provider>
)

const SomeComponent = () => {
  const value = useContext(myContext)
  return <p>Value: {value}</p>
}
상하문에서 제공하는 공급자를 장식하기 위해 맞춤형 공급자를 만드는 것이 매우 유용한 모델이다.예를 들어 공급업체가 해당 지역 주(실제로 전 세계에서 사용됨)를 어떻게 처리할 수 있는지 살펴보겠습니다.
const GlobalStateProvider = ({ initialState, children }) => {
  const [state, setState] = useState(initialState)
  return (
    <globalStateContext.Provider value={{ state, setState }}>
      {children}
    </globalStateContext.Provider>
  )
}
상하문은 현재 statesetState 속성을 가진 대상을 포함하고 있다.컨텍스트 사용자가 쉽게 사용할 수 있도록 사용자 정의 연결 두 개를 만들어 액세스합니다.
const useGlobalState = () => useContext(globalStateContext).state
const useSetGlobalState = () => useContext(globalStateContext).setState
우리는 현재 처음으로 실행 가능한 전 세계 국가 관리 실시 방안을 가지고 있다.이제 Redux의 핵심 개념을 어떻게 실현하여 상태 업데이트:reducer를 처리하는지 봅시다.

감속기
Reducer는 각 상태 속성을 업데이트하는 대신 작업을 사용하여 상태를 업데이트하는 우아한 방법을 제공합니다.
HTTP 요청이 완료되면 상태를 업데이트하려고 합니다.우리는 loading 로고를 false로 설정하여 업데이트하고 요청 결과를 result 속성에 넣기를 희망합니다.감속기에 대해서는 다음과 같은 조치를 고려할 수 있다.
{ type: 'request_succeeded', result: {...} }
이 동작은 매개 변수로 Reducer 함수에 전달됩니다.이것은 두 개의 매개 변수를 포함하는 함수입니다: 현재 상태와 조작입니다.전통적으로 동작은 type 속성을 가진 대상이고 이 동작에 특정한 다른 속성도 있을 수 있다.이 조작과 현재 상태를 바탕으로 Reducer 함수는 상태의 새로운 버전을 되돌려야 합니다.
우리는 이 감속기가 우리의 첫 번째 동작을 처리할 것이라고 상상할 수 있다.
const reducer = (state, action) => {
  switch (action.type) {
    case 'request_succeeded':
      return { ...state, loading: false, result: action.result }
    default:
      // If we don’t know the action type, we return
      // the current state unmodified.
      return state
  }
}
좋은 소식: React에 갈고리가 있습니다. 로컬 상태와 사용 작업의 업데이트를 처리하기 위해 Reducer를 사용할 수 있습니다. useReducer이것은 useState 개선 버전으로 볼 수 있지만, setter 함수를 되돌려 상태를 업데이트하지 않고, dispatch 함수를 되돌려 Reducer에 할당합니다.
const [state, dispatch] = useReducer(reducer, initialState)
예를 들어, initialState 매개변수에는 다음과 같은 객체가 포함될 수 있습니다.
const initialState = { loading: false, error: false, result: undefined }
작업을 통해 상태를 업데이트하려면 작업을 매개변수로 호출dispatch하기만 하면 됩니다.
dispatch({ type: 'request_succeeded', result: {...} })

컨텍스트의 글로벌 감속기
기왕 우리가 상하문과 감축기를 이해한 이상 우리는 상하문을 만들어서 감축기로 우리의 전체 상태를 처리할 수 있다.컨텍스트 객체를 먼저 작성합니다.
const storeContext = createContext()
그리고 상하문 StoreProvider 을 사용하여 Provider 구성 요소를 만듭니다.앞에서 보듯이, 우리의 상하문은 로컬 상태를 포함하지만, 우리는 useState 대신 useReducer 을 사용할 것이다.useReducer의 두 가지 매개 변수(감속기와 초기 상태)는 도구로 우리에게 전달됩니다StoreProvider:
const StoreProvider = ({ reducer, initialState, children }) => {
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <storeContext.Provider value={{ state, dispatch }}>
      {children}
    </storeContext.Provider>
  )
}
상하문을 저장하기 위해서, 우리는 두 개의 갈고리를 제공할 것입니다. 하나는 상태를 읽는 데 사용되고, 다른 하나는 스케줄링 작업에 사용됩니다.
전체 상태를 되돌려주는 갈고리만 만드는 것이 아니라, React Redux에서 제공하는 것과 같은 동작을 수행합니다. 갈고리는 선택기를 매개 변수로 합니다. 즉, 상태에서 우리가 흥미를 느끼는 값을 추출하는 함수입니다.
선택기는 일반적으로 매우 간단합니다.
const selectPlanet = (state) => state.planet
갈고리useSelector는 이 선택기를 매개 변수로 사용하여 올바른 상태로 되돌려줍니다.
const useSelector = (selector) => selector(useContext(storeContext).state)
마지막으로 useDispatch 갈고리는 상하문값에서 되돌아오는 dispatch 속성:
const useDispatch = () => useContext(storeContext).dispatch
우리의 실현은 이미 완성되었다. 코드는 십여 줄의 코드만 포함한다!물론 부작용을 처리하는 중간부품(Redux Thunk, Redux Saga 등) 등 Redux를 이렇게 강하게 하는 모든 기능을 실현하지는 못했다.그러나 Reducer 논리로 전역 상태를 추적하기 위해 Redux가 정말 필요한지 궁금하다.
다음은 Redux가 구현한 전체 코드입니다.
const storeContext = createContext()

export const StoreProvider = ({ reducer, initialState, children }) => {
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <storeContext.Provider value={{ state, dispatch }}>
      {children}
    </storeContext.Provider>
  )
}

const useSelector = (selector) => selector(useContext(storeContext).state)

const useDispatch = () => useContext(storeContext).dispatch

우리의 실현을 사용하다
우리의 Redux를 사용하면 실제 Redux를 사용하는 것과 매우 비슷해 보입니다.HTTP API를 호출하는 예제에서 이 점을 살펴보겠습니다.
먼저, 초기 상태, 복원기, 작업 작성자 및 선택기:
// Initial state
const initialState = {
  loading: false,
  error: false,
  planet: null,
}

// Reducer
const reducer = (state, action) => {
  switch (action.type) {
    case 'load':
      return { ...state, loading: true, error: false }
    case 'success':
      return { ...state, loading: false, planet: action.planet }
    case 'error':
      return { ...state, loading: false, error: true }
    default:
      return state
  }
}

// Action creators
const fetchStart = () => ({ type: 'load' })
const fetchSuccess = (planet) => ({ type: 'success', planet })
const fetchError = () => ({ type: 'error' })

// Selectors
const selectLoading = (state) => state.loading
const selectError = (state) => state.error
const selectPlanet = (state) => state.planet
그런 다음 상태에서 읽을 구성 요소를 만들고 이를 업데이트하기 위해 작업을 할당합니다.
const Planet = () => {
  const loading = useSelector(selectLoading)
  const error = useSelector(selectError)
  const planet = useSelector(selectPlanet)
  const dispatch = useDispatch()

  useEffect(() => {
    dispatch(fetchStart())
    fetch('https://swapi.dev/api/planets/1/')
      .then((res) => res.json())
      .then((planet) => {
        dispatch(fetchSuccess(planet))
      })
      .catch((error) => {
        console.error(error)
        dispatch(fetchError())
      })
  }, [])

  if (loading) {
    return <p>Loading…</p>
  } else if (error) {
    return <p>An error occurred.</p>
  } else if (planet) {
    return <p>Planet: {planet.name}</p>
  } else {
    return null
  }
}
마지막으로, 응용 프로그램 Planet 구성 요소를 상점의 공급자에 봉합합니다.
const App = () => {
  return (
    <StoreProvider reducer={reducer} initialState={initialState}>
      <Planet />
    </StoreProvider>
  )
}
이렇게!자신의 실현을 어떻게 작성하는지 이미 알고 있는 이상, Redux는 그렇게 신비롭지 않습니까?
만약 당신이 이 실현을 사용하고 싶다면, 나는 또한 만들었습니다 .
a CodeSandbox
보상: 다시 쓰기useReducer우리는 useReducer를 사용했다. 왜냐하면 이 갈고리는React에서 제공하기 때문이다.만약 그렇지 않다면, 그것도 다시 쓸 수 있고, 다섯 줄도 안 되는 코드만 있으면 된다는 것을 아십니까?
const useReducer = (reducer, initialState) => {
  const [state, setState] = useState(initialState)
  const dispatch = (action) => setState(reducer(state, action))
  return [state, dispatch]
}
만약 네가 이 글을 좋아한다면, 나는 나의 새 전자책 에서 React와 hooks를 상세하게 소개할 것이다.그것의 목표는 그들이 어떻게 일을 하는지, 어떻게 디버깅을 하는지, 그리고 그들이 초래할 수 있는 흔한 문제를 어떻게 해결하는지 이해하는 데 도움을 주는 것이다.
너도 괜찮다. 나는 그곳에서 React, hooks, frontend 및 기타 주제에 관한 글을 자주 발표한다😉

좋은 웹페이지 즐겨찾기