最近在学习react的hook,看完useContext后总结一下react中的三种实现祖孙数据共享的方式。
这是一个主题换肤的例子,分别用下面三种方式来实现。先上效果图:
下面是app.js中的代码:
import React from 'react';
import './App.css'
import PropsContext from './pages/props-context'
import ClassContext from './pages/class-context'
import UseContext from './pages/hook-context'
function App() {
return (
<div className="App">
{/* 使用props实现数据共享 */}
<PropsContext ></PropsContext >
<hr/>
{/* 使用class context实现数据共享 */}
<ClassContext></ClassContext>
<hr />
{/* 使用userContext hook实现数据共享 */}
<UseContext></UseContext>
</div>
);
}
export default App;
1. props-context
顾名思义使用props的方式将祖先组件的数据一层层传递给子组件。和vue一样,父组件通过自定义属性的方式将数据作为props传给子组件,不同的是react中可以传递一个HTML结构(实质上是可以通过JSX转换的js对象),render-props正是利用了这一点灵活渲染DOM实现自定义HTML结构。
import React, { Component } from 'react'
import './index.css'
const COLOR = ['#B5E61D', '#ED1C24', '#00A2E8', '#A349A4', '#B97A57', '#A349A4']
export default class grandfather extends Component {
state = {
theme: COLOR[0]
}
changeColor = () => {
this.setState({
theme: COLOR[Math.ceil(Math.random() * (COLOR.length - 1))] // 随机获取颜色
})
}
render() {
return (
<div className="grandfather">
<div>当前主题为:{this.state.theme}</div>
<div style={{ color: this.state.theme }}>grandfather</div>
<Father theme={this.state.theme}></Father>
<button className="fixed1" onClick={this.changeColor}>换肤</button>
</div>
)
}
}
function Father(props) {
return (
<div className="father">
<div style={{ color: props.theme }}>father</div>
<Son theme={props.theme}></Son>
</div>
)
}
function Son(props) {
return (
<div className="son">
<div style={{ color: props.theme }}>son</div>
</div>
)
}
2. class-context
在class类组件中使用context来将数据共享给子组件,不同于props-context,这种方式可以跨越N个父组件直接将数据传给子组件,并不需要父->子、父->子。。。链式传递。VUE中也有使用context来实现祖孙数据共享的方案,只不过人家叫provide-inject,而react中叫provide-consumer。
import React, { Component, createContext } from 'react'
import './index.css'
const COLOR = ['#B5E61D', '#ED1C24', '#00A2E8', '#A349A4', '#B97A57', '#A349A4']
const Theme = createContext(COLOR[1])
export default class grandfather extends Component {
state = {
theme: COLOR[0]
}
changeColor = () => {
this.setState({
theme: COLOR[Math.ceil(Math.random() * (COLOR.length - 1))] // 随机获取颜色
})
}
render() {
return (
<div className="grandfather">
<div>当前主题为:{this.state.theme}</div>
<div style={{ color: this.state.theme }}>grandfather</div>
<Theme.Provider value={this.state.theme}>
<Father></Father>
</Theme.Provider >
<button className="fixed2" onClick={this.changeColor}>换肤</button>
</div>
)
}
}
function Father(props) {
return (
<div className="father">
<Theme.Consumer>
{
(theme) => {
return <div style={{ color: theme }}>father</div>
}
}
</Theme.Consumer>
<Son></Son>
</div>
)
}
function Son(props) {
return (
<div className="son">
<Theme.Consumer>
{
(theme) => {
return <div style={{ color: theme }}>son</div>
}
}
</Theme.Consumer>
</div>
)
}
3. hook-context
hook中提供了useContext这个钩子配合createContext去实现爷孙数据共享。相当于是provide-useComtext模式。在hook中数据通过useState钩子存放,实参为初识值,返回值为存放的数据以及相应的改变这个数据的函数。
import React, { useState ,useContext, createContext } from 'react'
import './index.css'
const COLOR = ['#B5E61D', '#ED1C24', '#00A2E8', '#A349A4', '#B97A57', '#A349A4']
const Theme = createContext('#B5E61D')
export default function Grandfather() {
const [ theme, setTheme ] = useState(COLOR[0])
function changeColor() {
setTheme(COLOR[Math.ceil(Math.random() * (COLOR.length - 1))])
}
return (
<div className="grandfather">
<div>当前主题为:{theme}</div>
<div style={{ color: theme }}>grandfather</div>
<Theme.Provider value={theme}>
<Father></Father>
</Theme.Provider>
<button className="fixed3" onClick={changeColor}>换肤</button>
</div>
)
}
function Father(props) {
return (
<div className="father">
// 在函数组件中一样可以使用Context.Consumer语法来拿数据
<Theme.Consumer>
{
(theme) => <div style={{ color: theme }}>father</div>
}
</Theme.Consumer>
<Son></Son>
</div>
)
}
function Son(props) {
const theme = useContext(Theme) // 注意此处的Theme是开头createContext('#B5E61D')的返回值Theme
return (
<div className="son">
<div style={{ color: theme }}>son</div>
</div>
)
}