💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
## 父向子 ### Props React数据流动是单向的,父组件向子组件通信也是最常见的;父组件通过props向子组件传递需要的信息 Child.jsx ``` import React from 'react'; import PropTypes from 'prop-types'; export default function Child({ name }) { return <h1>Hello, {name}</h1>; } Child.propTypes = { name: PropTypes.string.isRequired, }; ``` ``` import React, { Component } from 'react'; import Child from './Child'; class Parent extends Component { render() { return ( <div> <Child name="Sara" /> </div> ); } } export default Parent; ``` ### Refs Refs 是使用`React.createRef()`创建的,并通过`ref`属性附加到 React 元素。在构造组件时,通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。 * 当`ref`属性用于 HTML 元素时,构造函数中使用`React.createRef()`创建的`ref`接收底层 DOM 元素作为其`current`属性。 * 当`ref`属性用于自定义 class 组件时,`ref`对象接收组件的挂载实例作为其`current`属性。 * **你不能在函数组件上使用`ref`属性**,因为他们没有实例。 ``` class Child extends React.Component { myFunc() { return "hello" } } class Parent extends React.Component { componentDidMount() { var x = this.foo.myFunc() // x is now 'hello' } render() { return ( <Child ref={foo => { this.foo = foo }} /> ) } } ``` ## 子向父 ### 利用回调函数 子组件通过调用父组件传来的回调函数,从而将数据传给父组件。 ``` const Child = ({ onClick }) => { <div onClick={() => onClick('zach')}>Click Me</div> } class Parent extends React.Component { handleClick = (data) => { console.log("Parent received value from child: " + data) } render() { return ( <Child onClick={this.handleClick} /> ) } } ``` ###. 利用自定义事件机制 这种方法其实跟react本身没有关系,我们利用的是原生dom元素的事件冒泡机制。 ``` class Parent extends React.Component { render() { return ( <div onClick={this.handleClick}> <Child /> </div> ); } handleClick = () => { console.log('clicked') } } function Child { return ( <button>Click</button> ); } ``` ## 兄弟组件 ### 通过共同父组件 ``` class Parent extends React.Component { constructor(props) { super(props) this.state = {count: 0} } setCount = () => { this.setState({count: this.state.count + 1}) } render() { return ( <div> <SiblingA count={this.state.count} /> <SiblingB onClick={this.setCount} /> </div> ); } } ``` ## 跨级组件、无相关关系的组件 ### Context ``` const ThemeContext = React.createContext('light'); class App extends React.Component { render() { return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } } function Toolbar() { return ( <div> <ThemedButton /> </div> ); } class ThemedButton extends React.Component { static contextType = ThemeContext; render() { return <Button theme={this.context} />; } } ``` 简单的解析一下: 1. `React.createContext`创建了一个Context对象,假如某个组件订阅了这个对象,当react去渲染这个组件时,会从离这个组件最近的一个`Provider`组件中读取当前的context值 2. `Context.Provider`: 每一个Context对象都有一个`Provider`属性,这个属性是一个react组件。在Provider组件以内的所有组件都可以通过它订阅context值的变动。具体来说,Provider组件有一个叫`value`的prop传递给所有内部组件,每当`value`的值发生变化时,Provider内部的组件都会根据新value值重新渲染 3. 那内部的组件该怎么使用这个context对象里的东西呢? a. 假如内部组件是用class声明的有状态组件:我们可以把Context对象赋值给这个类的属性`contextType`,如上面所示的ThemedButton组件 ``` class ThemedButton extends React.Component { static contextType = ThemeContext; render() { const value = this.context return <Button theme={value} />; } } ``` b. 假如内部组件是用function创建的无状态组件:我们可以使用`Context.Consumer`,这也是Context对象直接提供给我们的组件,这个组件接受一个函数作为自己的child,这个函数的入参就是context的value,并返回一个react组件。可以将上面的ThemedButton改写下: ``` function ThemedButton { return ( <ThemeContext.Consumer> {value => <Button theme={value} />} </ThemeContext.Consumer> ) } ``` 最后提一句,context对于解决react组件层级很深的props传递很有效,但也不应该被滥用。只有像theme、language等这种全局属性(很多组件都有可能依赖它们)时,才考虑用context。如果只是单纯为了解决层级很深的props传递,可以直接用[component composition](https://link.segmentfault.com/?enc=ocYc5MWTeXGADTzSENuxSA%3D%3D.JprVlKXFBTs9046VNwppqePK8AS5HvdkXahZWOTq2Pq2USAJ5yxbkolmLl63feKpbv%2FLKNExalJhFfbtJHtNZg%3D%3D) ### Redux [React中组件通信的几种方式](https://juejin.cn/post/6844903520500449288) [30分钟精通十种React组件之间通信的方法](https://segmentfault.com/a/1190000023585646)