본문 바로가기

FrontEnd

Lean Recoil 강의 정리 : Atoms And Selectors

반응형

https://learnrecoil.com/

 

스프레드시트
드롭다운 최상단으로 옮기면
스테이트 변경으로 전부 리렌더

 

상태가 리액트 바깥에 저장된다!!
데이터베이스나 엔티티랑 컴포넌트가 잘 맞으면 리코일을 안쓰는게 좋음. 쓰지말라는 말은 아님

Atom : 공유 상태 단위

기본적인 공유상태 해법은 상태를 상위 컴포넌트로 hoisting 하는 것이다.

상태를 위로 올리는게 가장 흔한 패턴

이는 props drilling및 불필요한 렌더링을 유발한다.

 

가장 기본적인 Recoil의 상태인 Atom을 이용하면, 상위 컴포넌트 (Atom)보다 하위에서 공유 상태를 사용할 수 있다.

Atom은 React 컴포넌트 밖에 존재한다는 것에 유의한다. 또한 key 충돌을 주의해야 한다.

값만 사용하려면 useRecoilValue를 사용한다.

const darkModeState = atom({
    key: 'darkMode',
    default: false,
})

const DarkModeSwitch = () => {
    const [darkMode, setDarkMode] = useRecoilState(darkModeState)

    return (
        <input
            type="checkbox"
            checked={darkMode}
            onChange={(event) => {
                setDarkMode(event.currentTarget.checked)
            }}
        />
    )
}

export const Button = () => {
    const darkMode = useRecoilValue(darkModeState)

    return (
        <button style={{backgroundColor: darkMode ? 'black' : 'white', color: darkMode ? 'white' : 'black'}}>
            My UI Button
        </button>
    )
}

export const Atoms = () => {
    return (
        <div>
            <div>
                <DarkModeSwitch />
            </div>
            <div>
                <Button />
            </div>
        </div>
    )
}

Selectors : 파생 상태

Selectors는 리덕스의 개념인 Single Source Of Truth를 보여준다.

작은 상태들을 조합하여 encapsulation하며, 변경하지 않고 다른 상태를 만든다.

eurSelector같은 단순 조회를 위한 파생 상태를 많이 만들 수 있다. 마치 CQRS를 보는 듯 하다.

// 계산의 기본이 되는 usd
const usdAtom = atom({
    key: 'usd',
    default: 1,
})

// 커미션 여부
const commissionEnabledAtom = atom({
    key: 'commissionEnabled',
    default: false,
})

// 커미션 크기
const commissionAtom = atom({
    key: 'commission',
    default: 5,
})

// 위의 3개의 상태를 조합하여 결과를 보여주는 셀렉터
const eurSelector = selector<number>({
    key: 'eur',
    get: ({get}) => {
        let usd = get(usdAtom)

        const commissionEnabled = get(commissionEnabledAtom)
        if (commissionEnabled) {
            const commission = get(commissionAtom)
            usd = removeCommission(usd, commission)
        }

        return usd * exchangeRate
    },
    set: ({set, get}, newEurValue) => {
        // @ts-ignore
        let newUsdValue = newEurValue / exchangeRate

        const commissionEnabled = get(commissionEnabledAtom)
        if (commissionEnabled) {
            const commission = get(commissionAtom)
            newUsdValue = addCommission(newUsdValue, commission)
        }

        set(usdAtom, newUsdValue)
    },
})
반응형