从两个不同的组件在 React 中传递状态

Passing state in React from two different components

我有一个 TopNab 栏(组件),其中包含一个 SearchBar 组件。我的主要组件正在呈现 TopNav、主要容器组件(配置文件)和页脚组件。我希望我的 SearchBar 组件将其状态传递给主容器组件,以便 Profile 组件可以使用它。

我正在尝试构建什么: 用户在搜索栏中键入名称并提交。 与用户名匹配的配置文件显示在主容器组件中。

现在我有一个可以呈现用户配置文件的组件。我还有一个组件,用于对用户提交的值进行状态更新。我需要做的是将此用户提交的值传递到我的配置文件组件,以便呈现正确的配置文件。

这是否可能,或者我是否需要重建我的组件以便搜索包含在配置文件组件中?

搜索栏

import React, { Component, PropTypes } from 'react';
import Profile from './Profile';


class SearchBar extends Component {
    constructor(props){
        super(props)
            this.state = {
                name: ''
            }
    }

    handleChange(e) {
        this.setState({
            name: e.target.value
        });
    }

    handleSubmit(e) {
            e.preventDefault();
            console.log("searching for NAME " + this.state.name);
            let profileName = this.state.name;
            //PASS STATE TO PROFILE COMPONENT
        }

    render() {
        return (
            <div>
                <form onSubmit={this.handleSubmit.bind(this)}>
                    ARMORY BETA
                    <input type="text" placeholder="Enter Name" 
                    name="name" 
                    value={this.state.name} 
                    onChange={this.handleChange.bind(this)} />
                    <button className="btn btn-success" type="submit">Search</button>
                </form>
            </div>
        )
    }
}

export default SearchBar;

简介

import React, { Component, PropTypes } from 'react';
import SearchBar from './SearchBar';
import ProfileContainer from '../containers/ProfileContainer';

class Profile extends Component {

    render() {
        return (
            <div className="cols2">
                <div>[IMG]</div>
                <div>
                    <ProfileContainer name={this.props.name}/>
                </div>
            </div>
        )
    }
}

Profile.PropTypes = {
    name: PropTypes.string
}

Profile.defaultProps = {
    name: ''
}

export default Profile;

主要

import React, { Component } from 'react';
import TopNav from './TopNav';
import Footer from './Footer';
import Profile from './Profile';

class Main extends Component {
    render() {
        return (
            <div className="container-fluid">
                <div className="row">
                    //TopNav calls SearchBar
                    <TopNav />
                </div>
                <div className="row">
                    <Profile />
                </div>
                <div className="row">
                    <Footer />
                </div>
            </div>
        )
    }
}


export default Main;

您需要在 SearchBar 上公开一个 属性 接受回调,该回调将被调用以向其父级指示表单已提交(例如 onSubmit)...

handleSubmit(e) {
        e.preventDefault();
        console.log("searching for NAME " + this.state.name);
        let profileName = this.state.name;
        //PASS STATE TO PROFILE COMPONENT
        this.props.onSubmit(yourFormData);
    }

...TopNav 不会处理 onSubmit 本身,而只是将其传递给它自己的父级(可能会沿途重命名为 "onSearchBarSubmit" 以使名称从 TopNav 的父级的角度更清晰) :

class TopNav extends Component {
    render() {
        return (
            <div className="container-fluid">
              <SearchBar onSubmit={this.props.onSearchBarSubmit}
            </div>
        );
    }
}

class Main extends Component {
    render() {
        return (
            <div className="container-fluid">
                <div className="row">
                    <TopNav onSearchBarSubmit={ (criteria) => this.searchForStuff(criteria) } />
                </div>
                <div className="row">
                    <Profile data={this.state.stuffYouGotBackFromSearch} />
                </div>
                <div className="row">
                    <Footer />
                </div>
            </div>
        )
    }
}

...或者,在某些情况下,可能需要取消嵌套组件,允许 SearchBar 作为 TopNavprops.children 之一。这允许您直接在 Main 中处理 onSubmit,并将它接收到的任何内容传递给 Profile:

class Main extends Component {
    render() {
        return (
            <div className="container-fluid">
                <div className="row">
                    //TopNav calls SearchBar
                    <TopNav>
                      <SearchBar onSubmit={ (criteria) => this.searchForStuff(criteria) } />
                    </TopNav>
                </div>
                <div className="row">
                    <Profile data={this.state.stuffYouGotBackFromSearch} />
                </div>
                <div className="row">
                    <Footer />
                </div>
            </div>
        )
    }
}

...取消嵌套的一个附带好处是它允许您独立使用 TopNav 和 Searchbar。

Main 中,您应该向 <TopNav /> 添加一个属性,该属性指向一个处理程序方法,该方法会将 profileName 状态更改传播回 Main。反过来,这将导致 Profile 被重新渲染。处理程序方法采用一个参数 profileName 并从 TopNav 中的 handleSubmit 方法调用。这是代码:

搜索栏

class SearchBar extends Component {
    . . .
    handleSubmit(e) {
        e.preventDefault();
        console.log("searching for NAME " + this.state.name);
        let profileName = this.state.name;
        this.props.handleProfileChange(profileName);
    }
    . . .
}
SearchBar.propTypes = {
  handleProfileChange: React.PropTypes.func.isRequired,
}

主要

class Main extends Component {
   constructor(props) {
     super(props);
     this.state = { profileName: '' }
     handleProfileChange = this.handleProfileChange.bind(this);
   }

   handleProfileChange(profileName) {
     // This state change will force Profile component to be re-rendered
     this.setState( { profileName });
   }

   render() {
     return (
        <div className="container-fluid">
            <div className="row">
                //TopNav calls SearchBar
                <TopNav handleProfileChange={this.handleProfileChange} />
            </div>
            <div className="row">
                <Profile profileName={this.state.profileName} />
            </div>
            <div className="row">
                <Footer />
            </div>
        </div>
    )
}