분류 Reactjs

useReducer로 useState를 구현하는 방법

컨텐츠 정보

  • 조회 540 (작성일 )

본문

이 두 가지 관련 후크의 차이점과 사용 사례를 이해하는 데 도움이 되는 재미있는 연습.


const useStateReducer = (prevState, newState) =>
2 typeof newState === 'function' ? newState(prevState) : newState
3
4const useStateInitializer = initialValue =>
5 typeof initialValue === 'function' ? initialValue() : initialValue
6
7function useState(initialValue) {
8 return React.useReducer(useStateReducer, initialValue, useStateInitializer)
9}


https://kentcdodds.com/blog/how-to-implement-usestate-with-usereducer 


하지만 켄트 ... 왜? 


재미를 위해 ? 또한 나는 물건을 재 구현하는 것이 어떻게 작동하는지 배울 수 있는 좋은 방법이라고 생각합니다.


React의 상태 관리 


React hooks는 상태 관리를 위한 useState와 useReducer의 두 가지 메커니즘을 제공합니다. 

흥미롭게도 React는 실제로 useReducer를 빌드하는 데 사용되는 동일한 코드에서 useState를 빌드합니다. 

구성 요소에서 단일 상태 값을 관리하는 것이 매우 일반적이기 때문에 이 작업을 수행하지만 useReducer를 사용하면 약간의 상용구가 필요합니다. 

따라서 useState를 통해 간단한 상태 관리 API를 노출하여 상용구를 줄입니다.


내부 코드를 모두 사용하면 이 작업을 수행 할 수 있다는 이점이 있지만 직접 수행 할 수도 있습니다 .?


useState API 


useState가 우리에게 노출하는 API를 살펴보면서 시작하겠습니다.


useState 함수 인수 : 


useState를 세 가지 다른 방법으로 호출 할 수 있습니다.


useState() // no initial value
useState(initialValue) // a literal initial value
useState(() => initialValue) // a lazy initial value

지연 초기 상태에 대해 자세히 알아보십시오 


따라서 새로운 useReducer 기반 useState는 이러한 모든 인수 변형을 지원해야 합니다.


useState 반환 값 


useState를 호출하면 상태 및 해당 상태를 업데이트 하기 위한 메커니즘 (일반적으로 "상태 업데이터 함수")이 반환됩니다. 이 함수는 새로운 상태 또는 이전 상태를 받아들이고 새로운 상태를 반환하는 함수로 호출 할 수 있습니다. 따라서 새로운 useReducer 기반 useState는 이러한 변형을 모두 지원해야 합니다.


const [state, setState] = useState()
setState(newState)
setState(previousState => newState)

이는 상태 업데이트 메커니즘을 "디스패치"기능이라고 하며 상태를 직접 설정하는 대신 실제 상태 업데이트 로직을 리듀서에 위임한다는 점을 제외하면 useReducer와 유사합니다.


useReducer API 


다음은 useReducer API입니다.


const [state, dispatch] = React.useReducer(reducerFn, initialValue) 


useReducer를 사용하면 초기화 지연을 원하면 초기화 함수 인 세 번째 인수를 제공하고 두 번째 인수는 해당 초기화 함수의 인수로 사용되므로 initialArg와 같은 이름으로 이름을 바꿀 수 있습니다.


const initializationFn = initialArg => initialArg
2
3const [state, dispatch] = useReducer(reducerFn, initialArg, initializationFn)


그리고 reducerFn은 디스패치 기능의 역할을 담당합니다. 따라서 디스패치 함수에 의해 상태가 업데이트 되는 방식을 제어하려면 디스패치가 호출되는 모든 것으로 호출되는 reducerFn을 통해 이를 수행 할 수 있습니다.


const reducerFn = (prevState, dispatchArg) => newState 


API를 사용하면 useState의 모든 기능을 구현할 수 있습니다.


useReducer 기반 useState 구현 


시작점은 다음과 같습니다.


const useStateReducer = () => {}

function useState() {
return React.useReducer(useStateReducer)
}

상태 업데이트 함수에 이 사용 사례를 구현하여 시작해 보겠습니다.


const [count, setCount] = useState(0)
setCount(count + 1)

따라서 디스패치 함수가 실제로 상태 값을 업데이트하도록해야합니다. 이를 위해 리듀서가 dispatchArg를 가져 와서 반환하도록 합니다.


const useStateReducer = (prevState, dispatchArg) => dispatchArg

function useState() {
return React.useReducer(useStateReducer)
}

그것으로 실제로 dispatchArg newState를 호출하는 것이 더 합리적입니다.


const useStateReducer = (prevState, newState) => newState

function useState() {
return React.useReducer(useStateReducer)
}


다음으로 useState API의 함수 업데이트 버전을 지원하겠습니다.


const [count, setCount] = useState(0)
setCount(previousCount => previousCount + 1)

이전 API를 계속 지원하려면 함수인지 여부와 이전 상태로 호출하는지 확인하기 위해 몇 가지 유형의 검사를 수행해야 합니다. 그렇지 않으면 우리는 그것을 반환합니다.


const useStateReducer = (prevState, newState) =>
typeof newState === 'function' ? newState(prevState) : newState

function useState() {
return React.useReducer(useStateReducer)
}

이제 초기 값으로 넘어 갑시다! 간단한 useState(0) 사례의 경우 실제로는 매우 간단합니다.


const useStateReducer = (prevState, newState) =>
typeof newState === 'function' ? newState(prevState) : newState

function useState(initialValue) {
return React.useReducer(useStateReducer, initialValue)
}


그러나 지연 버전은 어떻습니까? useState(() => 0) 여기서는 useReducer API가 약간 다르기 때문에 조금 까다롭습니다. 먼저 반복 해 봅시다. 지연되지 않은 useState(0) 사용 사례를 구현할 수 있는 또 다른 방법은 다음과 같습니다.


const useStateReducer = (prevState, newState) =>
typeof newState === 'function' ? newState(prevState) : newState

const useStateInitializer = initialArg => initialArg

function useState(initialValue) {
return React.useReducer(useStateReducer, initialValue, useStateInitializer)
}

이 경우 initialValue를 initialArg로 전달하고 useStateInitializer 함수는 단순히 해당 값을 반환합니다. 따라서 API의 지연 초기화 프로그램 버전을 보다 쉽게 ​​지원할 수 있습니다. initialArg가 함수인지 확인하기 만하면 되고, 호출하면 호출하고, 그렇지 않으면 반환합니다.


const useStateReducer = (prevState, newState) =>
typeof newState === 'function' ? newState(prevState) : newState

const useStateInitializer = initialValue =>
typeof initialValue === 'function' ? initialValue() : initialValue

function useState(initialValue) {
return React.useReducer(useStateReducer, initialValue, useStateInitializer)
}


결론 


이 API를 조금 더 파고 들기를 바랍니다. 내장 useState 후크를 계속 사용하는 것이 좋지만 useReducer가 얼마나 유연한 지 보는 것이 흥미로울 것이라고 생각했습니다. redux를 사용한 것과 같은 방법으로 사용할 필요는 없습니다 (실제로 일반적인 방법으로 redux를 사용할 필요는 없습니다. 또는 전혀).