10줄의 코드로 입력된 상태 관리 반응
목표
이 튜토리얼의 목표는 자바스크립트 코드에서 100% 유형 유추로 "강력한"상태 관리를 작성하는 것입니다.
TLDR:
Final example of the state management is available on github
또는 이 문서의 끝에서 완전히 작동하는 예제를 찾을 수 있습니다.
역사적 배경
React는 약 2년 전에 후크를 도입했습니다.
그것은 전체 생태계를 변화시켰고 외부를 사용하지 않고도 애플리케이션을 작성할 수 있음을 나타냅니다.
redux 또는 mobx와 같은 상태 관리 라이브러리와 우리는 여전히 멋진 미니멀리스트 코드를 갖게 될 것입니다.
후크가 도입되기 전에도 동일한 작업을 수행할 수 있었습니다.
하지만 문제는
renderProps
/HOC
/Classes
API가 후크만큼 훌륭하고 우아하지 않다는 것입니다.바닐라 리액트의 툴링은 여전히 꽤 강력하지만 애플리케이션이 있다면
평범한 인간에게는 너무 복잡한 수많은 코드 라인으로 다음을 수행할 수 있습니다.
일부 타사 상태 관리 라이브러리에 대해 생각하기 시작합니다.
사용자 정의 상태 관리 래퍼
React context는 글로벌 애플리케이션 로직의 일부를 다른 부분으로 분할하는 방법에 대한 좋은 옵션입니다.
파일을 만들고 각 모듈에 대해 새 파일
React.createContext
을 정의합니다.그런 다음 컨텍스트 인스턴스를 가져와
useContext
후크를 통해 구성 요소 인스턴스에서 사용합니다.이 패턴의 큰 특징은 변경된 상태에 직접 연결되지 않은 구성 요소를 다시 렌더링하지 않는다는 것입니다.
순수한 바닐라 React에서는 이와 같은 컨텍스트를 통해 상태 관리를 작성할 수 있습니다.
import React, { useState, useContext } from 'react'
const MyContext = React.createContext(null)
const LogicStateContextProvider = (props) => {
const [logicState, setLogicState] = useState(null)
return (
<MyContextontext.Provider value={{ logicState, setLogicState }}>
{...props}
</MyContextontext.Provider>
)
}
const Child = () => {
const logic = useContext(MyContext)
return <div />
}
const App = () => (
<LogicStateContextProvider>
<Child />
</LogicStateContextProvider>
)
Typescript 정적 유형을 추가하기 전까지는 모든 것이 좋아 보입니다.
그런 다음 각 정의
React.createContext
에 대해 새 데이터 유형을 정의해야 한다는 것을 알게 됩니다.
/* redundant unwanted line of static type */
type DefinedInterfaceForMyCContext = {
/* redundant unwanted line of static type */
logicState: null | string
/* redundant unwanted line of static type */
setLogicState: React.Dispatch<React.SetStateAction<boolean>>
/* redundant unwanted line of static type */
}
const MyContext = React.createContext<BoringToTypesTheseCha>(
null as any /* ts hack to omit default values */
)
const LogicStateContextProvider = (props) => {
const [logicState, setLogicState] = useState(null as null | string)
return (
<MyContext.Provider value={{ logicState, setLogicState }}>
{...props}
</MyContext.Provider>
)
}
/* ... */
보시다시피 각각
React.createContext
은 Typescript 정적 유형을 정의하기 위해 몇 줄을 추가로 사용합니다.원시 Javascript 구현에서 직접 쉽게 유추할 수 있습니다.
무엇보다 추론의 모든 문제가 JSX에서 비롯된다는 것을 알 수 있습니다. 데이터 유형을 추론하는 것은 불가능하지 않습니다!
따라서 구성 요소에서 원시 논리를 직접 추출하여
useLogicState
라는 사용자 지정 후크에 넣어야 합니다.const useLogicState = () => {
const [logicState, setLogicState] = useState(null as null | string)
return {
logicState,
setLogicState
}
}
const MyContext = React.createContext<
/* some Typescript generic magic */
ReturnType<typeof useLogicState>
>(
null as any /* ts hack to bypass default values */
)
const LogicStateContextProvider = (props) => {
const value = useLogicState()
return (
<MyContext.Provider value={value}>
{...props}
</MyContext.Provider>
)
}
const Child = () => {
const logic = useContext(MyContext)
return <div />
}
const App = () => (
<LogicStateContextProvider>
<Child />
</LogicStateContextProvider>
)
보시다시피 논리를 사용자 정의 후크로 분리하면
ReturnType<typeof customHook>
로 데이터 유형을 유추할 수 있습니다.이 TS 코드 줄
ReturnType<typeof useLogicState>
을 완전히 이해하지 못하는 경우 다른 Typescript 자습서를 확인할 수 있습니다.또한 코드에 포함해야 하는 중복 문자가 많다는 사실도 마음에 들지 않습니다.
새로운 React 컨텍스트를 생성할 때마다 자체 JSX
Provider
구성 요소가 우리의 <App />
를 래핑하는 데 사용됩니다.그래서 나는 모든 더러운 코드를 자체 함수로 추출하고 래핑하기로 결정했습니다.
덕분에 우리는 마법의 Typescript 제네릭을 이 함수로 옮길 수 있고 전체 상태 관리를 추론할 수 있습니다.
type Props = {
children: React.ReactNode
}
export const genericHookContextBuilder = <T, P>(hook: () => T) => {
const Context = React.createContext<T>(undefined as never)
return {
Context,
ContextProvider: (props: Props & P) => {
const value = hook()
return <Context.Provider value={value}>{props.children}</Context.Provider>
},
}
}
그래서 우리는 읽기 어려운 이 모든 마법을 10줄 함수로 감쌀 수 있습니다.
이제
genericHookContextBuilder
함수는 상태 후크를 인수로 사용하고 작동할 구성 요소를 생성합니다.useContext
로 가져올 수 있는 앱 래퍼 및 컨텍스트로 사용됩니다.다음 예제에서 사용할 준비가 되었습니다.
전체 예
import React, { useState, useContext } from 'react';
type Props = {
children: React.ReactNode
}
export const genericHookContextBuilder = <T, P>(hook: () => T) => {
const Context = React.createContext<T>(undefined as never)
return {
Context,
ContextProvider: (props: Props & P) => {
const value = hook()
return <Context.Provider value={value}>{props.children}</Context.Provider>
},
}
}
const useLogicState = () => {
const [logicState, setLogicState] = useState(null as null | string)
return {
logicState,
setLogicState
}
}
export const {
ContextProvider: LogicStateContextProvider,
Context: LogicStateContext,
} = genericHookContextBuilder(useLogicState)
const Child = () => {
const logic = useContext(LogicStateContext)
return <div />
}
const App = () => (
<LogicStateContextProvider>
<Child />
</LogicStateContextProvider>
)
보시다시피 기본 React 컨텍스트 기본 상세 API 주위에 작은 래퍼를 작성했습니다.
래퍼는 코드를 복제하지 않고 많은 추가 줄을 저장할 수 있는 즉시 사용 가능한 Typescript 유형 유추로 이를 향상시켰습니다.
이 기사를 나와 똑같이 즐기고 새로운 것을 배웠기를 바랍니다. 그렇다면 이 기사를 좋아하는 것을 잊지 마세요
Reference
이 문제에 관하여(10줄의 코드로 입력된 상태 관리 반응), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/svehla/react-typed-state-management-under-10-lines-of-code-1347텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)