组件通信
1.父子通信[具备相同父亲的兄弟组件]: props属性基于ref
2.祖先和后代 具备相同祖先的平行组件
父子组件通信
父子组件传值本质上还是传递属性的问题
props【父传子】
传值:
{/* 子组件 xxx为变量*/}
<Child xxx={xxx}/>
// 子组件接收参数
function Child(props){
let {xxx} = props
return (<div>{xxx}</div>)
}
回调函数【子传父】【单向数据流,需要借助回调函数去修改父组件的值】
子组件修改组件的值
{/* 子组件 这里的xxx为回调函数*/}
<Child xxx={xxx}/>
// 子组件接收参数
function Child(props){
let {xxx} = props
return (
// onClick 也可以为其他
<button onClick={xxx}>按钮</button>
)
}
写一个简单完整例子: 实现点击按钮,数据加1的简单操作
Demo为父组件,DemoMain、DemoChange 为子元素
Demo.jsx
import React, { useState } from 'react'
import DemoMain from './DemoMain';
import DemoChange from './DemoChange';
export default function Demo() {
const [count, setCount] = useState(0);
const change = () => {
setCount(count + 1);
}
return (
<div>
<div>总计:{count}</div>
<DemoMain count={count} />
<DemoChange change={change} />
</div>
)
}
DemoMain.jsx
import React from 'react'
export default function DemoMain(props) {
let { count } = props
return (
<div style={{ margin: '20px 0' }}>
展示内容:{count}
</div>
)
}
DemoChange.jsx
import React from 'react'
import { Button } from 'antd'
export default function DemoChange(props) {
let { change } = props
return (
<div>
<Button type="primary" onClick={change.bind(null)}>按钮</Button>
</div>
)
}
上面的例子主要为演示作用,实际开发以业务为准 Demo传值给DemoMain DemoMain使用props接收传递过来的参数 DemoChange 触发Demo内的change回调函数,来达到修改兄弟组件内的数据
这个等于也是兄弟组件之间使用值,依托于父组件,从而获取到值,达到兄弟组件之间交互的目的
运行结果:
祖先/后代(或平行)组件间通信
当组件之间的嵌套结构较深,如果基于属性一级一级传值会很麻烦!
上下文 React.createContext() 【代码较多】
上下文存入信息:
ThemeContext.Provider
基于上下文对象中,提供的Provider组件,用来:
- 向上下文中存储信息:value 属性指定的值就是要存储的信息
- 当祖先组件更新,render 重新执行,会把最新的狀态值,再次存储到上下文对象中!!
<ThemeContext.Provider value={{
count,
change
}}>
<div>
<div>总计:{count}</div>
<DemoMain />
<DemoChange />
</div>
</ThemeContext.Provider>
获取上下文传值方式
类组件
获取上下文
方案一: contextType
- 导入创建的上下文对象
- 给类组件设置静态私有属性 contextType = 上下文对象
- 从 this.context 获取需要的信息即可
import React, { Component } from 'react'
import ThemeContext from './ThemeContext';
import { Button } from 'antd'
export default class DemoChange extends Component {
// 类组件 获取上下文方式 第一种: contextType
static contextType = ThemeContext;
render() {
let { change } = this.context
return (
<div>
<Button type="primary" onClick={change}>按钮</Button>
</div >
)
}
}
第二种:Consumer 适用于函数组件及类组件
<ThemeContext.Consumer>
{
context => {
return 渲染的视图
}
}
</ThemeContext.Consumer>
上下文传值 例子:
下面存入及获取的方案都在例子里面写了:
Demo 存入上下文信息,类组件和函数组件存入的方式一致,都是 ThemeContext.Provider
DemoMain是函数组件
DemoChange是类组件
目录结构:
目录结构和上个例子一致,多了个ThemeContext.js
ThemeContext.js
import React from "react";
const ThemeContext = React.createContext();
export default ThemeContext;
Demo.jsx
import React, { useState } from 'react'
import ThemeContext from './ThemeContext';
import DemoMain from './DemoMain';
import DemoChange from './DemoChange';
export default function Demo() {
const [count, setCount] = useState(0);
const change = () => {
setCount(count + 1);
}
return (
<ThemeContext.Provider value={{
count,
change
}}>
<div>
<div>总计:{count}</div>
<DemoMain />
<DemoChange />
</div>
</ThemeContext.Provider>
)
}
DemoMain.jsx
import React, { useContext } from 'react'
import ThemeContext from './ThemeContext';
export default function DemoMain() {
// **** 函数组件 获取上下文方式 第一种: useContext
let { count } = useContext(ThemeContext)
return (
<div style={{ margin: '20px 0' }}>
展示内容:{count}
</div>
)
// **** 函数组件 获取上下文方式 第二种: Consumer
// return (
// <ThemeContext.Consumer>
// {context => {
// let { count } = context
// return (
// <div style={{ margin: '20px 0' }}>
// 展示内容:{count}
// </div>
// )
// }}
// </ThemeContext.Consumer>
// )
}
DemoChange.jsx
import React, { Component } from 'react'
import ThemeContext from './ThemeContext';
import { Button } from 'antd'
export default class DemoChange extends Component {
// 类组件 获取上下文方式 第一种: contextType
static contextType = ThemeContext;
render() {
let { change } = this.context
return (
<div>
<Button type="primary" onClick={change}>按钮</Button>
</div >
)
}
// ******* 类组件 获取上下文方式 第二种: Consumer
// render() {
// return (
// <ThemeContext.Consumer>
// {
// context => {
// let { change } = context
// return (
// <div>
// <Button type="primary" onClick={change}>按钮</Button>
// </div >
// )
// }
// }
// </ThemeContext.Consumer>
// )
// }
}