每个 React 利用都是由交互组件组成的。这些组件如何通信是 UI 体系结构的一个重要一环。随着应用程序变得更大、更简单,组件交互变得更加重要。
React 提供了多种办法来解决这种需要,每种办法都有其相应的用例。这次让咱们从最简略的亲子互动办法开始。
亲子与道具
组件之间最简略的通信模式是通过属性——通常称为道具(Props)。Props 是由父组件传递给子组件的参数,相似于函数的参数。
Props 容许将变量传递给子节点,当值产生更改时,它们会在子节点中自动更新,如 Listing 1 所示。
Listing 1. Props (class-based):
- function App(){
- return <div>
- <AppChild name=”Matt” />
- </div>
- }
- function AppChild(props){
- return <span>
- My name is {props.name}
- </span>
- }
- ReactDOM.render(<App />, document.getElementById(‘app’));
Listing 1 显示了如何在基于函数的组件树中解决 props。这个过程与类相似。这个基于函数的示例展现了函数款式的更精简的语法。
带性能道具的子 - 父组件
Listing 1 容许将值从父级传递给子级。当子节点须要更新父节点的变更时,它们不能仅批改属性。
如果你试图间接批改子过程的 prop,你会在控制台中看到以下类型的谬误:
- Uncaught TypeError: Cannot assign to read only property ‘foo’ of object ‘#<Object>’
相同,父过程能够传入一个功能性道具,子过程能够调用这个函数。这种性能道具是一种面向事件的编程。您能够在 Listing 2 中看到这一点。
Listing 2. Functional props
- function App(){
- const [name, setName] = React.useState(“Matt”);
- return <div>
- <AppChild name={name} onChangeName={()=>{setName(“John”)}}/>
- </div>
- }
- function AppChild(props){
- return <span>
- My name is {props.name}
- <button onClick={props.onChangeName}>Change Name</button>
- </span>
- }
- ReactDOM.render(<App />, document.getElementById(‘app’));
Listing 2 介绍了用于治理状态的 useState。这是一个简略的机制。functional prop 的实质是当按钮被点击时,App 组件传入的函数就会被执行。这样,就实现了子 - 父通信。
总的来说,要记住的概念是:道具流向子级,事件流向父级。这是一个有价值的设计准则,有助于放弃应用程序的组织性和可管理性。
向父级传递信息
通常状况下,子组件须要随它们的事件一起传递参数。这能够通过向函数道具回调增加参数来实现。如 Listing 3 所示。
- function App(){
- const [name, setName] = React.useState(“Matt”); //test
- return <div>
- <AppChild name={name} onChangeName={(newName)=>{setName(newName)}}/>
- </div>
- }
- function AppChild(props){
- return <span>
- My name is {props.name}
- <button onClick={()=>props.onChangeName(“Bill”)}>Change Name</button>
- </span>
- }
- 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
- // In the route definition:
- <Route path=’/foopath’render={(props) => <Child {…props} />} />
- // In the child component:
- <Route appProps={{onTitleChange}} />
从实质上讲,Listing 4 通过笼罩路由的出现形式容许间接传递属性。
同级沟通
到目前为止,咱们看到的个性提供了解决同级通信的能力。这在 React 文档中被称为“晋升状态”。
这里的思维是,当组件树的同一级别的子组件必须共享状态时,该状态将被推入父组件。而后父级通过道具将状态分享给须要它的子级。子节点引发事件以更新父节点的状态,这将主动在共享属性中反映进去。
React Context API
React 自身提供的另一个选项是 Context API。Context API 被设计用来治理简略的、有全局意义的值。也就是说,这些值被应用程序中的许多组件应用。
文档中给出的示例是一个主题设置。许多组件将会对这种设置感兴趣 (为了反映适当的主题),这与道具一起传递十分艰难。
Context API 不用于解决简单的应用程序数据,它是专门针对在深度嵌套的组件中防止简单的道具解决的。Listing 5 给出了一个简略的示例。
Listing 5. Context API
- // defining the context value
- <ThemeContext.Provider value=”dark”>
- // Consuming the context value later on
- <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 之类的更简单的选项能够解决这些更简单的需要。