前言
在上一篇文章《JSX详解》中我们了解了什么是jsx以及jsx的语法规则。
本文中我们将详细了解React父子组件通信方式。
React技能树
React 技能树
├── JSX
│ ├── 语法
│ ├── 元素渲染
│ ├── 组件
│ ├── Props
│ ├── State
│ └── 生命周期
├── 组件通信
│ ├── 父子组件通信
│ ├── 兄弟组件通信
│ ├── 跨级组件通信
│ ├── Context
│ └── Redux
├── 样式
│ ├── 内联样式
│ ├── CSS Modules
│ └── Styled Components
├── 路由
│ ├── React Router
│ ├── 动态路由
│ └── 嵌套路由
├── 数据请求
│ ├── Axios
│ ├── Fetch
│ └── GraphQL
├── 状态管理
│ ├── Redux
│ ├── MobX
│ └── Recoil
├── 常用库和框架
│ ├── Ant Design
│ ├── Material UI
│ ├── Bootstrap
│ ├── Semantic UI
│ └── Tailwind CSS
├── 测试
│ ├── Jest
│ ├── Enzyme
│ └── React Testing Library
├── 构建工具
│ ├── Webpack
│ └── Parcel
└── 服务端渲染
├── Next.js
└── Gatsby
通过 props 实现父子组件通信
React 组件之间的数据传递通常是通过 props 实现的。组件可以将数据作为 props 属性传递给其子组件,然后子组件可以使用这些数据来进行渲染或执行操作。
在下面的示例中,我们将展示如何通过 props 实现父子组件之间的通信。
我们创建一个包含两个组件的简单 React 应用程序:一个父组件 Parent 和一个子组件 Child。父组件有一个按钮,点击按钮将触发一个事件,事件将向子组件传递一个字符串类型的消息。子组件将通过 props 属性接收消息并在页面上显示。
// Parent.js
import React from 'react';
import Child from './Child';
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
message: '',
};
this.handleButtonClick = this.handleButtonClick.bind(this);
}
handleButtonClick() {
this.setState({
message: 'Hello from Parent!',
});
}
render() {
return (
<div>
<h1>Parent Component</h1>
<button onClick={
this.handleButtonClick}>Click me</button>
<Child message={
this.state.message} />
</div>
);
}
}
export default Parent;
// Child.js
import React from 'react';
class Child extends React.Component {
render() {
return (
<div>
<h2>Child Component</h2>
<p>{
this.props.message}</p>
</div>
);
}
}
export default Child;
在上述代码中,我们创建了一个 Parent 组件和一个 Child 组件,并将 Child 组件作为 Parent 组件的子组件进行渲染。
Parent 组件有一个按钮,并且通过 state 管理一个 message 状态。当按钮被点击时,Parent 组件会更新 message 状态,然后将 message 作为 props 属性传递给 Child 组件。Child 组件接收 message 属性并将其显示在页面上。
通过 state 实现父子组件通信
在某些情况下,组件之间的通信需要更为复杂的逻辑。在这种情况下,可以使用组件的状态来实现通信。子组件可以通过 props 属性接收来自父组件的数据,并将其存储在自己的状态中。然后,子组件可以通过 setState 方法更新自己的状态,并触发重新渲染。
在下面的示例中,我们将展示如何通过状态实现父子组件之间的通信。
我们创建一个父组件 Parent 和一个子组件 Child。父组件有一个按钮,点击按钮将触发一个事件,事件将更新父组件的状态并将其作为 props 属性传递给子组件。子组件将使用接收到的 props 属性来更新自己的状态,并在页面上显示。
// Parent.js
import React from 'react';
import Child from './Child';
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
message: '',
};
this.handleButtonClick = this.handleButtonClick.bind(this);
}
handleButtonClick() {
this.setState({
message: 'Hello from Parent!',
});
}
render() {
return (
<div>
<h1>Parent Component</h1>
<button onClick={
this.handleButtonClick}>Click me</button>
<Child message={
this.state.message} />
</div>
);
}
}
export default Parent;
// Child.js
import React from 'react';
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
message: '',
};
this.handleButtonClick = this.handleButtonClick.bind(this);
}
handleButtonClick() {
this.setState({
message: 'Hello from Child!',
});
}
render() {
return (
<div>
<h2>Child Component</h2>
<p>{
this.props.message}</p>
<button onClick={
this.handleButtonClick}>Click me</button>
<p>{
this.state.message}</p>
</div>
);
}
}
export default Child;
在上述代码中,我们创建了一个 Parent 组件和一个 Child 组件,并将 Child 组件作为 Parent 组件的子组件进行渲染。
Parent 组件有一个按钮,并且通过 state 管理一个 message 状态。当按钮被点击时,Parent 组件会更新 message 状态,然后将 message 作为 props 属性传递给 Child 组件。Child 组件接收 message 属性并将其显示在页面上。
同时,Child 组件也有一个按钮,当按钮被点击时,Child 组件会更新自己的状态并将其显示在页面上。
通过回调函数实现父子组件通信
有时候,我们需要将子组件中的数据传递回父组件,以便父组件可以执行一些操作或更新自己的状态。在这种情况下,可以通过将回调函数作为 props 属性传递给子组件来实现通信。子组件可以调用该回调函数,并将需要传递的数据作为参数传递给它。
在下面的示例中,我们将展示如何通过回调函数实现父子组件之间的通信。
我们创建一个父组件 Parent 和一个子组件 Child。子组件有一个输入框,当输入框中的值发生变化时,子组件将调用传递给它的回调函数,并将输入框中的值作为参数传递给它。父组件将接收到传递的值,并将其存储在自己的状态中。
// Parent.js
import React from 'react';
import Child from './Child';
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: '',
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(value) {
this.setState({
inputValue: value,
});
}
render() {
return (
<div>
<h1>Parent Component</h1>
<Child onInputChange={
this.handleInputChange} />
<p>Input value: {
this.state.inputValue}</p>
</div>
);
}
}
export default Parent;
```jsx
// Child.js
import React from 'react';
class Child extends React.Component {
constructor(props) {
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const value = event.target.value;
this.props.onInputChange(value);
}
render() {
return (
<div>
<h2>Child Component</h2>
<input type="text" onChange={
this.handleInputChange} />
</div>
);
}
}
export default Child;
在上述代码中,我们创建了一个父组件 Parent 和一个子组件 Child,并将 Child 组件作为 Parent 组件的子组件进行渲染。
Child 组件有一个输入框,并且通过 props 属性将一个回调函数 onInputChange 传递给 Parent 组件。当输入框中的值发生变化时,Child 组件将调用 onInputChange 回调函数,并将输入框中的值作为参数传递给它。Parent 组件接收到传递的值,并将其存储在自己的状态中。同时,Parent 组件将输入框中的值显示在页面上。
使用 React Context 实现组件通信
在某些情况下,如果您需要将数据传递给多个组件,或者您的组件层级很深,那么通过 props 属性将数据从一个组件传递到另一个组件可能会变得很繁琐。在这种情况下,可以使用 React Context 来共享数据并在组件之间进行通信。
React Context 是 React 16.3 版本中引入的一项新功能,它允许您在组件树中传递数据,而无需显式地通过 props 属性将数据传递下去。
使用 React Context,您可以创建一个“上下文”对象,其中包含需要共享的数据,然后将其传递给 React 组件树中的所有组件。这样,任何组件都可以访问该数据,而不需要通过 props 属性进行传递。
下面的示例演示了如何使用 React Context 实现组件通信。
我们创建了一个 ThemeContext 上下文对象,其中包含一个名为 theme 的属性。然后,我们创建了两个组件 Toolbar 和 Button。Toolbar 组件将从 ThemeContext 上下文中获取 theme 属性,并将其作为 props 属性传递给 Button 组件。Button 组件将使用接收到的 theme 属性来渲染自己的样式。
// ThemeContext.js
import React from 'react';
const ThemeContext = React.createContext('light');
export default ThemeContext;
// Toolbar.js
import React from 'react';
import Button from './Button';
import ThemeContext from './ThemeContext';
class Toolbar extends React.Component {
render() {
return (
<div>
<h1>Toolbar Component</h1>
<Button />
</div>
);
}
}
Toolbar.contextType = ThemeContext;
export default Toolbar;
// Button.js
import React from 'react';
import ThemeContext from './ThemeContext';
class Button extends React.Component {
render() {
const theme = this.context;
return (
<button style={
{
background: theme === 'dark' ? '#000' : '#fff', color: theme === 'dark' ? '#fff' : '#000' }}>
{
theme === 'dark' ? 'Dark' : 'Light'} Button
</button>
);
}
}
Button.contextType = ThemeContext;
export default Button;
在上述代码中,我们创建了一个名为 ThemeContext 的上下文对象,并将其导出为默认模块。我们还创建了两个组件 Toolbar 和 Button。Toolbar 组件是一个简单的组件,它包含一个标题和一个 Button 组件。
在 Toolbar 组件中,我们将 ThemeContext 上下文对象分配给了 contextType 类型的 static 类属性。这告诉 React,我们希望 Toolbar 组件可以访问 ThemeContext 上下文对象。然后,我们在 Toolbar 组件的 render 方法中,通过 this.context 属性访问 ThemeContext 上下文中的 theme 属性,并将其作为 props 属性传递给 Button 组件。
在 Button 组件中,我们也将 ThemeContext 上下文对象分配给了 contextType 类型的 static 类属性。然后,在 render 方法中,我们使用 this.context 属性访问 ThemeContext 上下文对象,并根据 theme 属性渲染不同的样式。
最后,我们可以在 App 组件中使用 ThemeContext.Provider 组件提供 theme 属性。任何在 ThemeContext.Provider 组件之下的组件都可以通过 contextType 类型的 static 类属性访问 ThemeContext 上下文对象,从而共享 theme 属性。
// App.js
import React from 'react';
import ThemeContext from './ThemeContext';
import Toolbar from './Toolbar';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: 'light',
};
this.toggleTheme = this.toggleTheme.bind(this);
}
toggleTheme() {
this.setState((state) => ({
theme: state.theme === 'light' ? 'dark' : 'light',
}));
}
render() {
return (
<div>
<h1>App Component</h1>
<button onClick={
this.toggleTheme}>Toggle Theme</button>
<ThemeContext.Provider value={
this.state.theme}>
<Toolbar />
</ThemeContext
</div>
);
}
}
export default App;
在上述代码中,我们在 App
组件中创建了一个名为 theme
的状态,其默认值为 light
。我们还创建了一个 toggleTheme
方法,该方法在点击按钮时切换 theme
状态的值。
在 render
方法中,我们使用 ThemeContext.Provider
组件提供了 theme
属性。该组件将 Toolbar
组件包装在其内部,从而使 Toolbar
组件和 Button
组件都可以访问 ThemeContext
上下文对象,并使用 theme
属性渲染不同的样式。
最后,我们将 App
组件导出为默认模块,以便在其他文件中使用它。
这是一个简单的示例,演示了如何在 React 中使用上下文实现组件通信。当需要在组件树中的多个组件之间共享数据时,使用上下文是一种非常有用的技术。
总结
在React中,父子组件最常用的4种通信方式:
- 通过 props 实现父子组件通信
- 通过 state 实现父子组件通信
- 通过回调函数实现父子组件通信
- 使用 React Context 实现组件通信
在项目实战过程中,可根据实际情况选择最合适的通信方式。
✍创作不易,求关注😄,点赞👍,收藏⭐️