Как получить доступ к состоянию ребенка в React?(React Hooks) - PullRequest
0 голосов
/ 15 февраля 2019

Как лучше всего получить доступ к состоянию ребенка с помощью реакционных хуков?

Я пробовал разные подходы.Ниже того, с чем я закончил.

Форма (родительская)


export const Form: FunctionComponent<IProps> = ({ onFinish, initState }) => {
  const formInputsStateRef = useRef({})

  const handleFinish = () => {
    const params = formInputsStateRef.current
    console.log(params)
    onFinish(params)
  }

  return (
    <div>
      <Inputs initState={initState} stateRef={formInputsStateRef}  />
      <S.Button onClick={handleFinish}>
        Finish
      </S.Button>
    </div>
  )
}

Входы (дочерняя)

export const Inputs: FunctionComponent<IProps> = ({ initState, stateRef }) => {
  const [pool, setPool] = useState(initState.pool)
  const [solarPanel, setSolarPanel] = useState(initState.solarPanel)

  useEffect(() => {
    stateRef.current = { pool, solarPanel }
  })

  const handlePoolInput = () => {
    setPool('new pool')
  }

  const handleSolarPanelInput = () => {
    setSolarPanel('new solar panel')
  }

  return (
    <div>
      <h2>{pool}</h2>
      <S.Button onClick={handlePoolInput}>Change pool</S.Button>
      <h2>{solarPanel}</h2>
      <S.Button onClick={handleSolarPanelInput}>Change solar panel</S.Button>
      <h2>-----</h2>
    </div>
  )
}

Так работает, но я нене нравится тот факт, что он создает объект на каждом рендере.


Входы (дочерние)

useEffect(() => {
    stateRef.current = { pool, solarPanel }
})

1 Ответ

0 голосов
/ 15 февраля 2019

Вы можете передать pool и solarPanel в качестве второго аргумента useEffect, чтобы состояние обновлялось до ref только при изменении этих значений

export const Inputs: FunctionComponent<IProps> = ({ initState, stateRef }) => {
  const [pool, setPool] = useState(initState.pool)
  const [solarPanel, setSolarPanel] = useState(initState.solarPanel)

  useEffect(() => {
    stateRef.current = { pool, solarPanel }
  }, [pool, solarPanel])

  const handlePoolInput = () => {
    setPool('new pool')
  }

  const handleSolarPanelInput = () => {
    setSolarPanel('new solar panel')
  }

  return (
    <div>
      <h2>{pool}</h2>
      <S.Button onClick={handlePoolInput}>Change pool</S.Button>
      <h2>{solarPanel}</h2>
      <S.Button onClick={handleSolarPanelInput}>Change solar panel</S.Button>
      <h2>-----</h2>
    </div>
  )
}

Однако, чтобы иметь более управляемый дескриптор дочерних значений, используяref, вы можете использовать useImperativeHandle hook.

Child

const InputsChild: FunctionComponent<IProps> = ({ initState, ref }) => {
  const [pool, setPool] = useState(initState.pool)
  const [solarPanel, setSolarPanel] = useState(initState.solarPanel)

  useImperativeHandle(ref, () => ({
    pool,
    solarPanel
  }), [pool, solarPanel])

  const handlePoolInput = () => {
    setPool('new pool')
  }

  const handleSolarPanelInput = () => {
    setSolarPanel('new solar panel')
  }

  return (
    <div>
      <h2>{pool}</h2>
      <S.Button onClick={handlePoolInput}>Change pool</S.Button>
      <h2>{solarPanel}</h2>
      <S.Button onClick={handleSolarPanelInput}>Change solar panel</S.Button>
      <h2>-----</h2>
    </div>
  )
}

export const Inputs = forwarRef(InputsChild);

Parent

export const Form: FunctionComponent<IProps> = ({ onFinish, initState }) => {
  const formInputsStateRef = useRef({})

  const handleFinish = () => {
    const params = formInputsStateRef.current
    console.log(params)
    onFinish(params)
  }

  return (
    <div>
      <Inputs initState={initState} ref={formInputsStateRef}  />
      <S.Button onClick={handleFinish}>
        Finish
      </S.Button>
    </div>
  )
}
...