4
votes

I have a component whose state is passed as a prop to a child component. I noticed that even if the Parent's state is changed, the child component is not re-rendered.

Based on the official React Documentation for utilizing shouldComponentUpdate:

"The first time the inner component gets rendered, it will have { foo: 'bar' } as the value prop. If the user clicks on the anchor, the parent component's state will get updated to { value: { foo: 'barbar' } }, triggering the re-rendering process of the inner component, which will receive { foo: 'barbar' } as the new value for the prop.

The problem is that since the parent and inner components share a reference to the same object, when the object gets mutated on line 2 of the onClick function, the prop the inner component had will change. So, when the re-rendering process starts, and shouldComponentUpdate gets invoked, this.props.value.foo will be equal to nextProps.value.foo, because in fact, this.props.value references the same object as nextProps.value.

Consequently, since we'll miss the change on the prop and short circuit the re-rendering process, the UI won't get updated from 'bar' to 'barbar'."

If I can't use shouldComponentUpdate, how would I force the child component to re-render based on a change of props from the Parent?

Parent Component

I want the child component to rerender based on the boolean given to showDropzone.

     <Dropzone 
      onDrop={this.onDrop} 
      clearFile = {this.clearFile}
      showDropzone = {this.state.filePresent}/>

Child Component

export default class Dropzone extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    const { onDrop } = this.props;
    const {showDropzone} = this.props;
    const {clearFile} = this.props;

    return (
      <div className="file-adder">
          <div className="preview">
            {{showDropzone}? 
            <Dropzone
              onDrop={onDrop}
              ref="dropzone">
            </Dropzone>           
            :<button type="button" 
            className="btn btn-primary"
            onClick={clearFile}>
            Clear File</button>}
        </div>
    </div>
    );
  }
}
2
Are you sure the naming is correct? The child component is called Dropzone, but its render function also renders a child <Dropzone>.wintvelt

2 Answers

2
votes

I'am sorry but your code has a lot of errors

First (This is a tip) inside:

 const { onDrop } = this.props;
 const { showDropzone } = this.props;
 const { clearFile } = this.props;

You can write just one line

 const { onDrop, showDropzone, clearFile } = this.props;

Now your problems starts from here:

You used showDropzone inside curly brackets and this is your problem remove them

Your mistake {{showDropzone}? firstOption : anotherOption }

Will be { showDropzone? firstOption : anotherOption }


Another mistake:

You used the Dropzone component inside itself and this is a big mistake

You can't use Dropzone component here {{showDropzone}? <Dropzone {...}/> : anotherOption } You can use it from another component


Finally i tried to format your code to make it like this

Parent Component

{ this.state.filePresent
   ? <Dropzone onDrop={this.onDrop} />
   : <button
         type="button" 
         className="btn btn-primary"
         onClick={clearFile}
         children="Clear File"
     />
}

Child Compnent

class Dropzone extends Component {
  render() {
    const { onDrop } = this.props;

    return (
      <div className="file-adder">
        <div className="preview" onDrop={onDrop} ref="dropzone">
          <p>Hi! This is Dropzone component</p>
        </div>
      </div>
    );
  }
}

export default Dropzone;
0
votes

In child component you have used "showZone" instead of "showDropzone".

Thanks