1
votes

I know that parents communicate with children through props and children to parents by invoking prop-functions.

I've been finding myself in situations where I have a child component where I'd like certain state to be kept. That child will invoke a prop-function and then update its state. Sometimes, though, I'd like the child to only update its state after the parent has finished processing. The parent might make a request to a server async. The traditional approach to handle this in JavaScript is to use a callback.

This feels like another vector for the parent to communicate with the child though. And that strikes me as a violation of React's data flow principles. Is my hesitation here justified? If so, this would just mean hoisting state up to the parent.

Here's an example to illustrate what I'm talking about. We have a form that is toggleable/collapsable. The ToggleableForm either displays a "+" or a Form component based on some state. When the Form propagates a submit event, ToggleableForm proxies that up to the parent, ToggleableFormContainer. We want to wait to collapse the form until we hear back from the server. ToggleableForm hands a callback object to handleFormSubmit. handleFormSubmit then uses those callback functions:

const ToggleableFormContainer = React.createClass({
  handleFormSubmit: function(cb) {
    $.ajax({
      url: self.props.url,
      dataType: 'json',
      cache: false,
      success: cb.onSuccess,
      error: cb.onError,
      },
    });
  },
  render: function() {
    return (
      <ToggleableForm onFormSubmit={this.handleFormSubmit} />
    );
  },
})

const ToggleableForm = React.createClass({
  getInitialState: function() {
    return {
      isOpen: false,
    };
  },
  handleOpen: function() {
    this.setState({ isOpen: true });
  },
  handleClose: function() {
    this.setState({ isOpen: false });
  },
  handleSubmit: function(data) {
    this.props.onFormSubmit(data, this.submitCallback);
  },
  submitCallback: {
    onSuccess: function() {
      this.setState({ isOpen: false });
    },
    onError: function() {
      // display error
    },
  },
  render: function() {
    if (this.state.isOpen) {
      return (
        <Form onFormSubmit={this.handleSubmit} onFormClose={this.handleClose} />
      );
    } else {
      return (
        <button onClick={this.handleOpen}>Open</button>
      );
    }
  },
});

Thanks!

1

1 Answers

0
votes

Pass submitResult as a prop. Set to null initially. Check for it in;

componentDidReceiveProps(nextProps) { 
  if (nextProps.submitResult) {
    if (nextProps.submitResult == "success") {
      this.setState({ isOpen: false });
    },
    else if (nextProps.submitResult == "error") {
      // display error
    },
  }
}