react中的三种方式实现祖孙数据共享

  • 时间:
  • 浏览:
  • 来源:互联网

最近在学习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>
  )
}

本文链接http://element-ui.cn/article/show-218960.aspx