Хранение ссылки на дочернюю функцию в parent - PullRequest
0 голосов
/ 30 мая 2018

У меня есть интересный вариант использования для хранения ссылок на функцию, которая принадлежит дочернему компоненту.Кроме того, я использую новый контекстный API React для передачи данных глубоко вложенным дочерним компонентам.

Я нашел ряд других ответов, которые касаются аналогичных проблем, но они не совсем соответствуют моему варианту использования.См. здесь и здесь .

Это проблема высокого уровня:

  1. A Provider компонент с именем <Parent /> содержит логикуи состояние, которое передается всем <Child /> компонентам, которые являются Consumers.
  2. Child компонентами, получает verify реквизит, который по сути является своего рода функцией валидатора для этого конкретного Child.Каждый вызов verify производит verificationResult на основе входящих изменений состояния от Parent.
  3. Важно, что все остальные компоненты Child должны быть уведомлены или знать о результате каждого verificationResult произведено его братьями и сестрами.
  4. Чтобы сделать вещи более интересными, я бы предпочел не хранить так называемые verificationResult каждого дочернего элемента в состоянии родителя, если мне не нужно, так как это по сути производное состояниеи может быть вычислено в Parent render().

Решение 1:

хранить verificationResult каждого дочернего элемента в Parent.Это можно сделать, подождав, пока соответствующее значение изменится в каждом Child componentDidUpdate(), например:

// Child.js
...
componentDidUpdate(pp) {
  const { hash, value, verify, setVerificationResult } = this.props

  // this check is a little more involved but 
  // the next line captures the gist of it. 
  if(pp.value[pp.hash] !== value[hash]) {
    setVerificationResult(hash, verify(value[hash], value))
  }
}
...

// Parent.js
...
setVerificationResult(hash, result) {
 this.setState(({ verificationResults }) => ({
    ...verificationResults, [hash]: result
 })) 
}
...

Примечание:

  • this.props.value и this.props.setVerificationResult получены от Parent, который является контекстом Provider, тогда как

  • this.props.hash и this.props.verify передаются вChild компонент напрямую.

this.props.hash захватывает часть value, о которой этот конкретный Child должен знать.

<code>// MyComponent.js

render() {
  return (
    ...
    <Child 
      hash="someHash"
      verify={(value, allValues) => {
        return value === 42 && allValues["anotherHash"] === 42
      }}
      render={({ verificationResults }) => (
        <pre>{JSON.stringify(verificationResults["someHash"], null, ' ')}
)} />...)

Решение 1 соответствует принципу однонаправленного потока данных, который стимулирует реакцию.Однако у меня есть 2 проблемы с этим решением.Во-первых, мне нужно хранить то, что по сути является состоянием, которое можно получить.Во-вторых, вызов setVerificationResult() вызовет нежелательный повторный рендеринг.Не говоря уже о дополнительной логике в componentDidUpdate

Решение 2

Следующие параметры выглядят примерно так.Обратите внимание, что я попытался показать только важные биты:

// Child.js
...
componentDidMount() {
  const { register } = this.props
  register(this.verify)
}

verify(values) {
  const { hash, verify } = this.props
  return { [hash]: verify(values[hash], values) }
}
...

// Parent.js
constructor(props)
  super(props)
  this.tests = [] 
  this.state = { 
    value: null, 
    // other initial state
  }
  ...
}

register(verifyFunc) {
  this.tests.push(verifyFunc)
}

render() {
  const { value } = this.sate
  let result = {}
  this.tests.forEach(test => result = { ...result, ...test(value) })
  return (
    <Provider 
      value={{
        ...this.state,
        verificationResults: result,
        register: this.register,
        // other things...
     }}
    >
      {this.props.children}
    </Provider>
  )
}

Обратите внимание, что во втором решении я не сохраняю никаких дополнительных состояний, так как оно рассчитывается на лету.Однако я храню ссылки на функцию в дочернем компоненте.

Может кто-нибудь сказать мне, почему НЕ использовать решение 2?Какие-нибудь альтернативные предложения о том, как заставить это работать?

Дополнительные примечания:

  • Почему бы не передать функцию проверки напрямую Родителю?Я мог бы, но это не сделало бы для очень чистого API.
  • Вы можете предположить, что я выполняю необходимую очистку при размонтировании и т. Д.
  • Проблема более сложная, чемпоказано здесь - на самом деле есть глубоко вложенные потребители, которые взаимодействуют с «локальным» поставщиком, который «разделяет» значения и логику до тех пор, пока они не достигают так называемых конечных компонентов, в то время как «главный» поставщик используется в качестве корневого узла, содержащего все состояние компонента илогика в иерархии компонентов.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...