Toggle Switch

11285 단어 React후크
오늘은 iOS에서 친숙한 Toggle Switch입니다.
code: github/$ yarn 1204






컴포넌트의 사용감은 다음과 같다. props 는 모두 optional 로, 형태 정의대로 버튼마다 지정이 가능합니다.
<ToggleSwitch />
type Props = {
  width?: number
  height?: number
  inactiveColor?: string
  activeColor?: string
  defaultChecked?: boolean
  onChangeChecked?: (checked: boolean) => void
  className?: string
}

useToggleSwitch



이번에 정의하는 Custom Hooks입니다. useEffect 에서는, checked 의 변경에 반응해 props 로부터 받아들이는 callback handler 를 두드립니다. state 스키마는 간단하고, checked 만을 보관 유지하고 있습니다.
type State = {
  checked: boolean
}
function useToggleSwitch(props: Props) {
  const [state, update] = useState<State>(...)
  const options = useMemo(...)
  const nodeStyle = useMemo(...)
  const baseStyle = useMemo(...)
  const knobStyle = useMemo(...)
  const inputStyle = useMemo(...)
  const handleToggle = useCallback(...)
  useEffect(...)
  return {
    state,
    nodeStyle,
    baseStyle,
    knobStyle,
    inputStyle,
    handleToggle
  }
}


Optional Injection



State와는 별도로 Custom Hooks 내부에서 "Options"를 유지하여 너비, 높이, 색상을 변경할 수 있습니다. 선택적이므로 지정된 값을 생성하는 defaultOptions 함수를 정의합니다.
const defaultOptions = (): Options => ({
  width: 50,
  height: 30,
  inactiveColor: '#eee',
  activeColor: '#4ed164'
})

useMemo 로 memoize 하면서, 규정치와 props 를 병합하는 처리를 실시하는 것으로, 로직에 필요한 설정치를 확보합니다. lodash.merge 를 사용하면 번거로운 undefined 병합 처리를 단순화할 수 있습니다.
const options = useMemo(
  (): Options =>
    merge(defaultOptions(), {
      width: props.width,
      height: props.height,
      inactiveColor: props.inactiveColor,
      activeColor: props.activeColor,
      onChangeChecked: props.onChangeChecked
    }),
  [
    props.width,
    props.height,
    props.inactiveColor,
    props.activeColor,
    props.onChangeChecked
  ]
)

useState 에 의한 값 보존과의 차이는 「props 에 의한 영향을 초기 한정으로 할까, 계속적으로 영향을 받는가」입니다. useState 로 확보된 state 는, 초기 마운트시 이후, props 의 변경을 받아들이지 않습니다. 변경하려면 동시에 생성된 업데이트 함수를 활용해야 합니다. Custom Hooks를 이용하는 Component에서는 다음과 같이 Optional Injection을 받습니다.
const View = (props: Props) => {
  const {
    state,
    nodeStyle,
    baseStyle,
    knobStyle,
    handleToggle
  } = useToggleSwitch({
    width: props.width,
    height: props.height,
    checked: props.defaultChecked,
    inactiveColor: props.inactiveColor,
    activeColor: props.activeColor,
    onChangeChecked: props.onChangeChecked
  })
  return (
    <div className={props.className} style={nodeStyle}>
      <span className="base" style={baseStyle} />
      <span className="knob" style={knobStyle} />
      <input
        type="checkbox"
        onChange={handleToggle}
        checked={state.checked}
      />
    </div>
  )
}

불필요한 일반화는 NG



오늘의 샘플은 범용화를 위한 테크닉으로서 Optional Injection 을 소개했습니다. 제품 코드에서 이러한 일반화가 항상 필요한 것은 아닙니다. 범용화를 필요 최소한으로 유지하는 것도 때때로 필요합니다.

좋은 웹페이지 즐겨찾기