Update component state from outside React (on server response)

I'm in the process of learning React. At the moment I have several components chained as parent-child, communication across them is done easily with callbacks.

I have a table (react component) and a small modal ajax form (no react). When I receive the response (an item) from the server I would like to add the item to the table.

My main question is, is it possible to trigger a component state change from outside react (in this case on server response)?


Solution 1:

Can you trigger a component state change outside a component?

Yes. Heres a simple example

In your react component set up a globally available closure which will update it's state when the function is fired.

componentDidMount(){
 globalVar.callback = (data) => {
    // `this` refers to our react component
    this.setState({...});     
  };
}

Then when your ajax'd response comes back you can fire the event with the returned data

globalVar.callback(data);

Or for something more robust, use a custom event or subscription

Solution 2:

component state best practice is to hold truly internal state data, not of interest outside component. If you must change a component from new external data use props, just change props from outside and the component rerender will react to changes.

Based on new props the component may use them on the rerender, or change state as did it in the constructor. The correct place to this task is in componentWillReceiveProps, in this method you can change state from new props without get into an eternal loop.

UPDATE: from react 16.3 componentWillReceiveProps is deprecated and getDerivedStateFromProps must be used, with improved detection of bad use cases and side effects. See https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

Solution 3:

There is a newer version of how to affect state on this article and it's codepen example.

It seems that this part of code

  render() {
    return (
      <div onClick={this.increment}>
        <div>Parent Value - {this.state.counter} - Click to increment</div>
        <ChildComponent ref={(childComponent) => {window.childComponent = childComponent}}/>
      </div>
    )
  }

does the trick.

We populate the window object with references of our child components - if we have - passing properties like ref={(childComponent) => {window.childComponent = childComponent}. Now window.childComponent access methods from the child component that can get/set the state.

The original codepen only attempts to read the state so I extended it to write too. The trick is a new method

setStateExt = (state) => {
    this.setState(this.state = state);
  }

see there.