Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
287 views
in Technique[技术] by (71.8m points)

reactjs - Storing reference to child function in parent

I have an interesting use case for storing references to a function that belongs to a child component. As an aside, I'm using the React's new context API to pass data to deeply nested children components.

I have found a number of other answers that address similar problems, but they dont quite match my use case. See here and here.

This is the high level problem:

  1. A Provider component called <Parent /> contains logic and state that is passed to all the <Child /> components which are the Consumers.
  2. Child components receive a verify prop that is essentially a validator function of sorts for that particular Child. Each call to verify produces a verificationResult based on incoming state changes from the the Parent.
  3. Importantly, all the other Child components must be notified or be aware of the result of each verificationResult produced by its siblings.
  4. To make things extra interesting, I'd prefer not to store the so called verificationResult of each child in the parent's state if I dont have to since it is essentially derived state and can be computed in Parent render().

Solution 1:

store verificationResult of each child in Parent. This could be done by waiting for the relevant value to change in each Child's componentDidUpdate()like so:

// 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
 })) 
}
...

Note:

  • this.props.value and this.props.setVerificationResult is received from the Parent which is a context Provider, while

  • this.props.hash and this.props.verify are passed to the Child component directly.

this.props.hash grabs the portion of value which this particular Child needs to know about.

// MyComponent.js

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

Solution 1 conforms to unidirectional data flow principle that react encourages. However I have 2 issues with this solution. Firstly, I'm having to store what is essentially state that can be derived. Secondly, calling setVerificationResult() will cause an unwanted re-render. Not to mention the additional logic in componentDidUpdate

Solution 2

The next options looks something like this. Note that I've tried show only the important bits:

// 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>
  )
}

Notice that in the second solution I'm not storing any additional state since its just calculated on the fly. However I am storing references to a function on a child component.

Can anyone tell me why NOT to use solution 2? Any alternative suggestions on how to make this work?

Additional notes:

  • Why not pass the verify function to the Parent directly? I could, but it wouldn't make for a very clean API.
  • You can assume that I'm performing the necessary clean up on unmount, etc.
  • The problem is more complex than shown here - there are in fact deeply nested Consumers that communicate with a "local" Provider which "splits" values and logic until they reach so called leaf Components, while a "Master" Provider is used as the root node containing all component state and logic in the hierarchy of components.
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...