이 포스트는 아래 출처의 글을 번역한 글 입니다. 오역과 의역이 있을 수 있습니다.
이 포스트는 기록을 남기기 위한 이유로 이곳에 존재합니다. an updated version of this blog post with React Hooks
이 글을 읽어주세요! 또한 보다 일반적인 개념인 "제어의 역전"에도 관심이 있을 수 있습니다.
지난주 @notruth(downshift 프로젝트의 새로운 컨트리뷰터)는 "closeOnSelection" 속성(박스에서 복수 선택을 했을시) 이슈를 추가해주었습니다. 여러분이 진정으로 알아야 할 것은 특정 시나리오에서 유저의 동작에 기초하여 downshift가 어떻게 상태를 업데이트하는지에 대한 결정이 @notruth가 구현에 대해 원하는 것과 일치하지 않는다는 것입니다.
Why do we use UI libraries?
같은 UI 라이브러리들을 이용하면 두개를 제공해 줄 수 있습니다.
- 이것이 동작하는 방식
- 어떻게 이것을 보일 것인지
UI 라이브러리들은 이러한 것들에 대해 결정을 내려야 합니다. 그러나 의사 결정이 적을수록 일반적으로 유용하고 유연한 라이브러리를 사용할 수 있습니다. 그러나 이것은 섬세한 균형입니다. 의사결정이 많을 수록 특정 경우에는 더 유용할 수 있지만 하지만 다른 사용사례에서는 완전히 사용을 못할 정도가 될 수도 있습니다. 만약 아무런 결정도 내리지 않는다면 음... 왜 라이브러리를 설치해야 할까요? 🤔
downshift 에서는 render prop을 이용하여 보여주는 방식에 대해 어떠한 결정도 내리지 않기로 결정하였습니다. 이렇게 결정한 이유는 "enhance input components" (autocomplete 같이) 에서 우리가 추상화 하고자 하는 부분은 동작하는 방식이고 좀 더 유연성을 부여해야 하는 부분은 보여지는 방식이기 때문입니다. 게다가 render prop을 사용하면 다른 사람들이 downshift위에 컴포넌트를 만들어 보기 좋게 제공하려 하는 것은 사소한 일입니다.(아직 아무도 그렇게 하지 않은 것에 대해 약간 놀랐습니다.) 🤨
Imperfect assumptions
가끔 downshift의 동작에 대해 결정을 내렸던 것이 사람들이 downshift를 사용하고자 하는 모든 경우에 완벽히 만족되지 못하는 경우가 있습니다. 예를들면 downshift는 사용자들이 item을 선택하거나 @notruth가 게시한 이슈와 같은 상황일때 `isOpen` 메뉴 상태를 `false`로 설정할 것입니다. 그들은 결정이 그들의 경우에 들어맞지 않는다고 말하곤 합니다. 🤷♂️
이게 제가 downshift에 제어 props를 제공하는 이유중 하나입니다. 이로 인해 downshift의 내부 상태를 완벽히 제어할 수 있습니다. 이러한 경우 @notruth는 `isOpen` 상태를 제어할 수 있고 `onStateChange`를 이용하여 상태 버전을 언제 업데이트 해야하는지 알 수 있습니다. 하지만 그것은 양이 많은 작업이기에 왜 @notruth가 더 쉬운 방법을 선호하는지 이해할 수 있습니다. 그러나 새로운 prop을 추가하는 것에 대한 제안은 downshift의 측면에서 API 비용을 증가시켜 이득을 제공해주는것 같지 않아보입니다. 그래서 어떻게 하면 단순화 할수 있고 boilerplate를 줄일 수 있을지 좀 더 고민해보기로 하였습니다. 😈
A simpler API
그때 저는 `modifyStateChange`라고 부르는 새로운 prop을 떠올렸습니다. downshift는 이미 control pops를 지원하고 있었기에 상태 변화를 `internalSetState`라고 불리는 내부 메서드로 분리 하였습니다. 이것은 놀랍게도 오래된 method 입니다. 고립은 새로운 기능의 구현을 사소한 것으로 만들어 줍니다. 우리가 상태변화를 만들때마다 먼저 Downshift 사용자가 곧 일어날 상태 변경에 관심이 있는지 보기 위한 method를 호출합니다. 🤓
이것을 위해 중요한 요소는 어떠한 종류의 상태 변화가 일어나는지 결정하는 사용자의 능력입니다. @notruth의 경우 사용자가 아이템을 선택했을때 `isOpen`이 `false`로 바뀌지 않기를 원했습니다. 그러므로 그들은 상황이 발생했을때 어떠한 종류의 변화가 필요한지 알아야 합니다. 운이 좋게도, 우리는 `onStateChange`에서도 이 구별이 필요했고 이미 이 메커니즘을 가지고 있었습니다! 이것은 `stateChangeTypes`로 불립니다. (여기에 리스트가 있습니다.) 🤖
그래서 @notruth는 pull request를 생성하고 `modifyStatechange`를 추가하였습니다. 조금 더 고민후에 다른 라이브러리들에게 유용할 수 있는 패턴으로 일반화 하는것이 가능하다고 결론지었습니다. 패턴들은 이름이 있어야 전달이 훨씬 쉬워져서 찾아보았습니다. 🕵️
Introducing the state reducer pattern
결국 `state reduer`라는 이름을 지었고 API를 악간 변경하였습니다. 당신의 함수는 두개의 인자를 받습니다 1) downshift의 현재상태, 2) 발생할 변화. 여러분의 일은 발생시키길 원하는 변화를 줄이는 것입니다. 또한 발생할 변화는 `stateChangeTypes`와 상응하는 `type`을 가지고 있습니다. 그래서 로직을 적용할지 안할지를 알수 있습니다. `changes`를 redux의 "action"으로서 생각할 수도 있습니다. 그러나 당신이 반환할것은 전체 상태가 아닙니다 변경하길 원하는 상태만 반환하면 됩니다. 🔁
A few people have since let me know that `reason-react` has something similar to this called simply "reducer" which is validating because I think Reason is pretty neat. 💡
더 이상 말할것 없이 아이템 선택후에 메뉴가 닫히는것을 예방하는 downshift에서의 단순한 "state reducer" 실행이 있습니다.
`stateReducer` prop이 있습니다.
import Downshift from 'downshift'
function stateReducer(state, changes) {
switch (changes.type) {
case Downshift.stateChangesTypes.keyDownEnter :
case Downshift.stateChangesTypes.clickItem:
return {
...changes,
isOpen: state.isOpen,
highlightedIndex: state.highlightedIndex,
}
default :
return chages
}
}
이것은 느슨한 API입니다. 그러나 downshift 내의 상태들이 제어될수 있기 때문에(control props를 통하든) 이것은 실제로 당신이 아직 성취할 수 없었던 것을 할 수 있게 해주지는 않고 boilerplate를 줄여주고 downshift에서 동작을 위해 필요한 변경사항을 줄여줄 뿐입니다. 👌
downshift에서의 구현은 간단하지는 않을 수 있습니다(downshift는 단순한 컴포넌트가 아닙니다). 이것이 제가 토글 컴포넌트의 간단한 구현 예시를 만든 이유입니다. https://codesandbox.io/s/4qo58nvl3x 토글 컴포넌트 치고는 과한 작업이지만, 이 패턴을 구현하는데 하나의 방법을 이해할 수 있기를 바랍니다. 🤝
Conclusion
이 새로운 패턴에 정말 흥분되고 제어 컴포넌트와 비제어컴포넌트 사이에 이 패턴이 존재할 수 있음을 발견하였습니다. 제어 props 패턴을 사용함으로써 요구되는 boilerplate와 추가 작업 없이 우리의 라이브러리가 이것이 동작하는 방식의 더 많은 경우를 충족시켰다는 것에 잘한일이라고 생각합니다. Good luck! 👍
출처 : https://kentcdodds.com/blog/the-state-reducer-pattern
'Frontend > React' 카테고리의 다른 글
React One Simple trick to optimize React re-renders (번역글) 🤔 (0) | 2022.04.27 |
---|---|
React The State Reducer Pattern with React Hooks (번역글) 🤔 (0) | 2022.04.24 |
React React-query InfiniteQuery 예제 ∞ (0) | 2022.04.23 |
React 글자 4개로 React 컴포넌트 최적화 가능(번역글) 🤔 (0) | 2022.04.20 |
React conatiner/presentational -> hook 📝 (0) | 2022.04.20 |