简单聊下 React 中祖孙级组件之间的通信方式
介绍
本文主要通过两种方式实现,一是通过 components,一是通过 hooks,通过 cdn 方式引入,阅读大概需要 7-8 min。
hooks 实现需要 react 版本在 16.8 以上
准备
- react.development.js 文件 - 用于操作 React 相关 api
- react-dom.development.js 文件 - 用于把 React 组件渲染成 DOM
- babel.min.js 文件 - 用于把 jsx 语法转化为 js
具体实现如下:如果没有可方便去 react_extends 项目 grandson_communication 分支 上查看,项目代码都附属到上面了
<script src="../js/17.0.1/react.development.js"></script>
<script src="../js/17.0.1/react-dom.development.js"></script>
<script src="../js/17.0.1/babel.min.js"></script>
<script type="text/babel">
// some js
</script>
方式一:components 实现
基本准备如下:
点击查看代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Components</title>
</head>
<body>
<div id="root"></div>
<script src="../js/17.0.1/react.development.js"></script>
<script src="../js/17.0.1/react-dom.development.js"></script>
<script src="../js/17.0.1/babel.min.js"></script>
<script type="text/babel">
class Father extends React.Component {
render() {
return (
<div>
father <ChildA />
</div>
)
}
}
class ChildA extends React.Component {
render() {
return (
<div>
ChildA <ChildB />
</div>
)
}
}
class ChildB extends React.Component {
render() {
return (
<div>
ChildB <ChildC />
</div>
)
}
}
class ChildC extends React.Component {
render() {
return <div>ChildC</div>
}
}
ReactDOM.render(<Father />, document.getElementById('root'))
</script>
</body>
</html>
这里实现了几个组件的逐级嵌套,依次是 Father > ChildA > ChildB > ChildC,下面说下祖孙级传参的具体实现的几个核心点
- 引入 React.createContext 变量
- 解构出 Provider、Consumer
- Provider 包裹子组件,并通过 value 属性传入需要传递的参数
这里的 Provider 和 Consumer 都是 Context 下的组件,想要具体了解的小伙伴可 翻阅官网 Context,推荐直接看下面代码,简洁明了。
如果使用了 Provider,那么 value 属性一定要传
具体实现:
点击查看代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Components</title>
</head>
<body>
<div id="root"></div>
<script src="../js/17.0.1/react.development.js"></script>
<script src="../js/17.0.1/react-dom.development.js"></script>
<script src="../js/17.0.1/babel.min.js"></script>
<script type="text/babel">
const myComponentContent = React.createContext() // 引入 context 变量
const { Provider, Consumer } = myComponentContent // 解构出对应的组件
class Father extends React.Component {
render() {
return (
<div>
father
<Provider value={{ id: 1, name: 'zxn', text: '我是一段文本' }}>
<ChildA />
</Provider>
</div>
)
}
}
class ChildA extends React.Component {
static contextType = myComponentContent
render() {
const { id, name, text } = this.context
return (
<div>
ChildA
<div>
我是从 Father 组件引入的变量,分别是 id: {id}、name: {name}
、text:{text}
</div>
<ChildB />
</div>
)
}
}
class ChildB extends React.Component {
static contextType = myComponentContent
render() {
const { id } = this.context
return (
<div>
ChildB
<div>我是从 Father 组件引入的变量,我只用了 id: {id}</div>
<ChildC />
</div>
)
}
}
class ChildC extends React.Component {
render() {
return (
<div>
ChildC
<Consumer>
{(value) => {
return (
<div>
我是从 Father 组件引入的变量,我采用了回调形式,我只用了
name: {value.name}
</div>
)
}}
</Consumer>
</div>
)
}
}
ReactDOM.render(<Father />, document.getElementById('root'))
</script>
</body>
</html>
方式二:hooks 实现
简单说下 hooks 存在的意义,它解决了哪些问题:
- 简化了 class 形式创建组件的代码量
- 允许函数式组件使用 class 组件的状态和生命周期
- 可拆分为更细粒度的函数,更方便复用
简单说下它如何使用:
- 把上面的 class 组件全部改为 函数组件
- 引入 Context 变量的流程不变
- 变的只有在具体的子组件引用时的写法,去除了必须声明 static 静态方法的步骤
具体实现:
点击查看代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hooks</title>
</head>
<body>
<div id="root"></div>
<script src="../js/17.0.1/react.development.js"></script>
<script src="../js/17.0.1/react-dom.development.js"></script>
<script src="../js/17.0.1/babel.min.js"></script>
<script type="text/babel">
const myComponentContent = React.createContext() // 引入 context 变量
const { Provider, Consumer } = myComponentContent // 结构出对应的组件
function Father() {
return (
<div>
father
<Provider value={{ id: 1, name: 'zxn', text: '我是一段文本' }}>
<ChildA />
</Provider>
</div>
)
}
function ChildA() {
const { id, name, text } = React.useContext(myComponentContent)
return (
<div>
ChildA
<div>
我是从 Father 组件引入的变量,分别是 id: {id}、name: {name}
、text:{text}
</div>
<ChildB />
</div>
)
}
function ChildB() {
const { id } = React.useContext(myComponentContent)
return (
<div>
ChildB
<div>我是从 Father 组件引入的变量,我只用了 id: {id}</div>
<ChildC />
</div>
)
}
function ChildC() {
return (
<div>
ChildC
<Consumer>
{(value) => {
return (
<div>
我是从 Father 组件引入的变量,我采用了回调形式,我只用了
name: {value.name}
</div>
)
}}
</Consumer>
</div>
)
}
ReactDOM.render(<Father />, document.getElementById('root'))
</script>
</body>
</html>
这里要注意下,使用函数式组件的时候,render 就不需要了,直接 return 就好
最后
稍微加了点粉色,最终实现效果皆为如下: