从两个不同的组件在 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
作为 TopNav
的 props.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>
)
}
我有一个 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
作为 TopNav
的 props.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>
)
}