一、父组件向子组件通信

React 数据流动是单向的,父组件向子组件的 通信也是最常见的方式。父组件通过 props 向子组件传递需要的信息

function EmailInput(props) {  return (    <label>      Email: <input value={props.email} />    </label>  );}const element = <EmailInput email="123124132@163.com" />;ReactDOM.render(  element,  document.getElementById('root'));

二、子组件向父组件通信

回调函数

function EmailInput(props) {  return (    <label>      Email: <input value={props.email} onChange={props.onChangeEmail} />    </label>  );}class App extends React.Component{   constructor(props){     super(props);     this.state = {       email: ''     }   }   onChangeEmail(e) => {     console.log(e.target.value)     this.setState({       email: e.target.value     });   }   render(){     let { email } = this.state;     return (       <EmailInput email={ eamil } onChangeEmail={this.onChangeEmail} />;     )   }}ReactDOM.render(  <APP />,  document.getElementById('root'));

三、跨级组件通信Context

Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言

不使用Context的情况

class App extends React.Component {  render() {    return <Toolbar theme="dark" />;  }}function Toolbar(props) {  // Toolbar 组件接受一个额外的“theme”属性,然后传递给 ThemedButton 组件。  // 如果应用中每一个单独的按钮都需要知道 theme 的值,这会是件很麻烦的事,  // 因为必须将这个值层层传递所有组件。  return (    <div>      <ThemedButton theme={props.theme} />    </div>  );}class ThemedButton extends React.Component {  render() {    return <Button theme={this.props.theme} />;  }}

使用Context的情况

// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。// 为当前的 theme 创建一个 context(“light”为默认值)。const ThemeContext = React.createContext('light');class App extends React.Component {  render() {    // 使用一个 Provider 来将当前的 theme 传递给以下的组件树。    // 无论多深,任何组件都能读取这个值。    // 在这个例子中,我们将 “dark” 作为当前的值传递下去。    return (      <ThemeContext.Provider value="dark">        <Toolbar />      </ThemeContext.Provider>    );  }}// 中间的组件再也不必指明往下传递 theme 了。function Toolbar() {  return (    <div>      <ThemedButton />    </div>  );}class ThemedButton extends React.Component {  // 指定 contextType 读取当前的 theme context。  // React 会往上找到最近的 theme Provider,然后使用它的值。  // 在这个例子中,当前的 theme 值为 “dark”。  static contextType = ThemeContext;  render() {    return <Button theme={this.context} />;  }}

Context 主要应用场景在于很多不同层级的组件需要访问同样一些的数据。请谨慎使用,因为这会使得组件的复用性变差。使用 context 比较好的场景是真正意义上的全局信息且不会更改,例如界面主题、用户信息等
如果你只是想避免层层传递一些属性,组件组合(component composition)有时候是一个比 context 更好的解决方案

props层层传递user和avatarSize

<Page user={user} avatarSize={avatarSize} />// ... 渲染出 ...<PageLayout user={user} avatarSize={avatarSize} />// ... 渲染出 ...<NavigationBar user={user} avatarSize={avatarSize} />// ... 渲染出 ...<Link href={user.permalink}>  <Avatar user={user} size={avatarSize} /></Link>

将Avatar组件自身向下传递

function Page(props) {  const user = props.user;  const userLink = (    <Link href={user.permalink}>      <Avatar user={user} size={props.avatarSize} />    </Link>  );  return <PageLayout userLink={userLink} />;}// 现在,我们有这样的组件:<Page user={user} avatarSize={avatarSize} />// ... 渲染出 ...<PageLayout userLink={...} />// ... 渲染出 ...<NavigationBar userLink={...} />// ... 渲染出 ...{props.userLink}

这种对组件组合减少了在你的应用中要传递的 props 数量,这在很多场景下会使得你的代码更加干净,使你对根组件有更多的把控。但是,这并不适用于每一个场景:这种将逻辑提升到组件树的更高层次来处理,会使得这些高层组件变得更复杂,并且会强行将低层组件适应这样的形式,这可能不会是你想要的

而且你的组件并不限制于接收单个子组件。你可能会传递多个子组件,甚至会为这些子组件(children)封装多个单独的“接口(slots)”,React 元素本质就是对象(object),所以你可以把它们当作 props,像其他数据一样传递。这种方法可能使你想起别的库中“槽”(slot)的概念,但在 React 中没有“槽”这一概念的限制,你可以将任何东西作为 props 进行传递。

function Page(props) {  const user = props.user;  const content = <Feed user={user} />;  const topBar = (    <NavigationBar>      <Link href={user.permalink}>        <Avatar user={user} size={props.avatarSize} />      </Link>    </NavigationBar>  );  return (    <PageLayout      topBar={topBar}      content={content}    />  );}