简体   繁体   中英

Passing state from child to parent in React; child has separate state

I have three components, from outermost to innermost: App => Welcome => SearchBar . There's a state defined in App and SearchBar , but what I want is to get the user-inputted data in SearchBar and display that in a "Results" page. As such, I'm trying to update the state in SearchBar and have that simultaneously update the state in App , so that I can pass that data on to another component that's a child of App (eg Results ). I have the following code, but it's only updating the state in SearchBar and not that in App .

(I've looked at some examples where the child (in this case SearchBar ) doesn't have its own state, but in this case I think it's necessary since I'm tracking user input. I may be wrong though.)

// App.js
export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: "" };
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(event) {
    event.preventDefault();
    this.setState({
      value: event.target.value
    });
  }

  render() {
    return (
      <Router>
        <div className="AppContainer">
          <Route
            exact
            path="/"
            render={props => <SearchBar handleSubmit={this.handleSubmit} />}
          />
...

// Welcome.js
export default class Welcome extends React.Component {
  render() {
    return (
      <div>
        <SearchBar handleSubmit={this.props.handleSubmit} />
      </div>
...

// SearchBar.js
export default class SearchBar extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: "" };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    event.preventDefault();
    this.setState({ value: event.target.value });
  }

  render() {
    return (
      <form onSubmit={this.props.handleSubmit}>
        <input
          type="text"
          placeholder="Search..."
          onChange={this.handleChange}
          value={this.state.value}
        />
        <input type="submit" />
      </form>
    );
  }
}

Then again, I'm quite new to React so this might not be a pattern that you're supposed to use. In any case, I would appreciate advice on how to best solve this.

Since you've already defined a handleSubmit() event-handler in App.js and passed it all the way down to your SearchBar.js component. You can extrapolate the data you need by giving the input tag in your SearchBar a name prop.

class Searchbar extends React.Component {
  state = {
    value: ""
  };

  handleOnChange = e => {
    this.setState({
      value: e.target.value
    });
  };

  render() {
    return (
      <form onSubmit={this.props.handleSubmit}>
        <input
          onChange={this.handleOnChange}
          value={this.state.value}
          name="search"
        />
      </form>
    );
  }
}

Then in App.js handleSubmit handler, target that name prop to get the value in the input.

  handleSubmit = e => {
    e.preventDefault();
    this.setState({
       value: e.target.search.value
    })
  };

This will likely have the least amount of re-renders.

Edit:

Yes we can totally display a new component upon submitting the form. We just need the help of a second state-value like displayResults or displayComponent then by using a simple if-check, we'll just toggle what components to show. See working example: Code Demo

In SearchBar component you should pass state value directly to handleSubmit function as,

<form onSubmit={(e)=>{e.preventDefault(); this.props.handleSubmit(this.state.value)}}>

In App component your handleSubmit function should be,

handleSubmit(inputValue) {
    this.setState({
      value: inputValue
    });
}

Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM