У меня есть интересный вариант использования для хранения ссылок на функцию, которая принадлежит дочернему компоненту.Кроме того, я использую новый контекстный API React для передачи данных глубоко вложенным дочерним компонентам.
Я нашел ряд других ответов, которые касаются аналогичных проблем, но они не совсем соответствуют моему варианту использования.См. здесь и здесь .
Это проблема высокого уровня:
- A
Provider
компонент с именем <Parent />
содержит логикуи состояние, которое передается всем <Child />
компонентам, которые являются Consumers
. Child
компонентами, получает verify
реквизит, который по сути является своего рода функцией валидатора для этого конкретного Child
.Каждый вызов verify
производит verificationResult
на основе входящих изменений состояния от Parent
. - Важно, что все остальные компоненты
Child
должны быть уведомлены или знать о результате каждого verificationResult
произведено его братьями и сестрами. - Чтобы сделать вещи более интересными, я бы предпочел не хранить так называемые
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.
- Вы можете предположить, что я выполняю необходимую очистку при размонтировании и т. Д.
- Проблема более сложная, чемпоказано здесь - на самом деле есть глубоко вложенные потребители, которые взаимодействуют с «локальным» поставщиком, который «разделяет» значения и логику до тех пор, пока они не достигают так называемых конечных компонентов, в то время как «главный» поставщик используется в качестве корневого узла, содержащего все состояние компонента илогика в иерархии компонентов.