每个React利用都是由交互组件组成的。这些组件如何通信是UI体系结构的一个重要一环。随着应用程序变得更大、更简单,组件交互变得更加重要。

React提供了多种办法来解决这种需要,每种办法都有其相应的用例。这次让咱们从最简略的亲子互动办法开始。

亲子与道具

组件之间最简略的通信模式是通过属性——通常称为道具(Props)。Props是由父组件传递给子组件的参数,相似于函数的参数。

Props容许将变量传递给子节点,当值产生更改时,它们会在子节点中自动更新,如Listing 1所示。

Listing 1. Props (class-based):

  1. function App(){ 
  2. return <div> 
  3. <AppChild name="Matt" /> 
  4. </div> 
  5. function AppChild(props){ 
  6. return <span> 
  7. My name is {props.name} 
  8. </span> 
  9. ReactDOM.render(<App />, document.getElementById('app')); 

Listing 1显示了如何在基于函数的组件树中解决props。这个过程与类相似。这个基于函数的示例展现了函数款式的更精简的语法。

带性能道具的子-父组件

Listing 1容许将值从父级传递给子级。当子节点须要更新父节点的变更时,它们不能仅批改属性。

如果你试图间接批改子过程的prop,你会在控制台中看到以下类型的谬误:

  1. Uncaught TypeError: Cannot assign to read only property 'foo' of object '#<Object>' 

相同,父过程能够传入一个功能性道具,子过程能够调用这个函数。这种性能道具是一种面向事件的编程。您能够在Listing 2中看到这一点。

Listing 2. Functional props

  1. function App(){ 
  2. const [name, setName] = React.useState("Matt"); 
  3. return <div> 
  4. <AppChild name={name} onChangeName={()=>{setName("John")}}/> 
  5. </div> 
  6. function AppChild(props){ 
  7. return <span> 
  8. My name is {props.name} 
  9. <button onClick={props.onChangeName}>Change Name</button> 
  10. </span> 
  11. ReactDOM.render(<App />, document.getElementById('app')); 

Listing 2介绍了用于治理状态的useState。这是一个简略的机制。functional prop的实质是当按钮被点击时,App组件传入的函数就会被执行。这样,就实现了子-父通信。

总的来说,要记住的概念是:道具流向子级,事件流向父级。这是一个有价值的设计准则,有助于放弃应用程序的组织性和可管理性。

向父级传递信息

通常状况下,子组件须要随它们的事件一起传递参数。这能够通过向函数道具回调增加参数来实现。如Listing 3所示。

  1. function App(){ 
  2. const [name, setName] = React.useState("Matt"); //test 
  3. return <div> 
  4. <AppChild name={name} onChangeName={(newName)=>{setName(newName)}}/> 
  5. </div> 
  6. function AppChild(props){ 
  7. return <span> 
  8. My name is {props.name} 
  9. <button onClick={()=>props.onChangeName("Bill")}>Change Name</button> 
  10. </span> 
  11. ReactDOM.render(<App />, document.getElementById('app')); 

留神 Listing 3中的 onClick={()=>props.onChangeName("Bill")}行。这里,咱们应用箭头语法创立一个匿名函数,其中蕴含咱们想要的参数。传递一个由组件自身批改的变量也很简略,语法如下:onClick={(myVar)=>prop . onchange (myVar)}。

顺便阐明一下,作为事件处理程序的内联箭头函数有时会因为性能问题而受到批评,只管这可能被言过其实。

性能道具和React Router

另一个重要的用例是在 React Router 之间传递参数。Listing 4提供了如何实现这一点的示例。

Listing 4. Passing functional props through Router

  1. // In the route definition: 
  2. <Route path=’/foopath’ render={(props) => <Child {…props} />} /> 
  3. // In the child component: 
  4. <Route appProps={{ onTitleChange }} /> 

从实质上讲,Listing 4通过笼罩路由的出现形式容许间接传递属性。

同级沟通

到目前为止,咱们看到的个性提供了解决同级通信的能力。这在React文档中被称为“晋升状态”。

这里的思维是,当组件树的同一级别的子组件必须共享状态时,该状态将被推入父组件。而后父级通过道具将状态分享给须要它的子级。子节点引发事件以更新父节点的状态,这将主动在共享属性中反映进去。

React Context API

React自身提供的另一个选项是Context API。Context API被设计用来治理简略的、有全局意义的值。也就是说,这些值被应用程序中的许多组件应用。

文档中给出的示例是一个主题设置。许多组件将会对这种设置感兴趣(为了反映适当的主题),这与道具一起传递十分艰难。

Context API不用于解决简单的应用程序数据,它是专门针对在深度嵌套的组件中防止简单的道具解决的。Listing 5给出了一个简略的示例。

Listing 5. Context API

  1. // defining the context value 
  2. <ThemeContext.Provider value="dark"> 
  3. // Consuming the context value later on 
  4. <Button theme={this.context} />; 

Redux的集中状态

更简单的应用程序可能须要更简单的状态架构。在React中解决这个问题最常见的库依然是Redux。Redux不仅仅是一个集中式存储,它更是一个自以为是的结构化事件零碎。

Redux的核心思想是,组件通过称为dispatchers的非凡对象引发事件(在Redux中称为动作)。这些动作事件由reducer察看到,而后reducer将动作利用到状态。而后,视图中的组件会自动更新以反映状态。

从这段简短的形容能够看出,Redux为您的应用程序引入了相当多的复杂性和正式性。在应用Redux时,这应该与结构化和可了解性的益处进行审慎的均衡。

还有其余治理集中商店的办法,包含MobX等。只管这些解决方案可能比Redux有劣势,但必须衡量Redux的风行所带来的劣势,即相熟度和理解它的开发人员的可用性。

React通过props和function props提供了十分弱小和简略的组件交互。在更大,更简单的应用程序中,这种办法可能会解体。利用诸如Context API和Redux之类的更简单的选项能够解决这些更简单的需要。