React中Context详解

172 阅读2分钟

旧的context

mport React from 'react';
import ReactDOM, { render } from 'react-dom'

import PropTypes from 'prop-types';

class App extends React.Component{
    getChildContext() {
        return {color: "purple"};
      }
    getChildContext(){
        return {
            color:"pusrplesss"
        }
    }
   render(){
       return <div>
           <Father></Father>
       </div>
   }
}

App.childContextTypes ={
    color: PropTypes.string
}


function Father(){
    return <div>
        <Child>
        </Child>
    </div>
}

class Child extends  React.Component{
    render(){
        return <div>
            得到context中的数据:{this.context.color}
        </div>
    }
}


Child.contextTypes = {
    color: PropTypes.string
}


  
ReactDOM.render(<App/>, document.getElementById("root"))

旧的context实现跨组件传值主要依靠子组件定义contextTypes属性,父组件中定义childcontextTypes,以及还需要在父组件中定义context的值,这个值可以有getChildContext方法实现

注意:几乎没有什么合适的方式去改变context的值,所有不要轻易修改context中的数据

createContext:provider提供数据 consumer接收数据

import React from 'react';
import ReactDOM from 'react-dom'

let ContextThe = React.createContext('light');
class App extends React.Component {
    render() {
        return (
            <ContextThe.Provider value="theme">
                <Toolbar />
            </ContextThe.Provider>
        )
    }
}

function Toolbar(props) {
    return (
        <ThemedButton />
    );
}

function ThemedButton() {
    return (
        <ContextThe.Consumer>
            {color => (
                <div>
                   {color}
                </div>
            )}
        </ContextThe.Consumer >
    )
}

ReactDOM.render(<App />, document.getElementById("root"))

createContext会得到一个对象,这个对象包含Porvider和Consumer属性,Porvider提供数据,Consumer包含的子组件可以取得context中的值

context另外一种不使用Consumer方式

import React from 'react';
import ReactDOM from 'react-dom'

let ContextThe = React.createContext('light');
class App extends React.Component {
    render() {
        return (
            <ContextThe.Provider value="theme">
                <Toolbar />
            </ContextThe.Provider>
        )
    }
}

function Toolbar(props) {
    return (
        <ThemedButton />
    );
}

class ThemedButton extends React.Component {
    static contextType = ContextThe;
    render() {
        return (
            <div>
                获取context中的值为:{this.context}
            </div>
        )

    }
}

ReactDOM.render(<App />, document.getElementById("root"))

这种方式通过在子组件中给contextType赋值,便可以拿到context中的值

多个context一起使用

// Theme context,默认的 theme 是 “light” 值
const ThemeContext = React.createContext('light');

// 用户登录 context
const UserContext = React.createContext({
  name: 'Guest',
});

class App extends React.Component {
  render() {
    const {signedInUser, theme} = this.props;

    // 提供初始 context 值的 App 组件
    return (
      <ThemeContext.Provider value={theme}>
        <UserContext.Provider value={signedInUser}>
          <Layout />
        </UserContext.Provider>
      </ThemeContext.Provider>
    );
  }
}

function Layout() {
  return (
    <div>
      <Sidebar />
      <Content />
    </div>
  );
}

// 一个组件可能会消费多个 context
function Content() {
  return (
    <ThemeContext.Consumer>
      {theme => (
        <UserContext.Consumer>
          {user => (
            <ProfilePage user={user} theme={theme} />
          )}
        </UserContext.Consumer>
      )}
    </ThemeContext.Consumer>
  );
}

可以通过嵌套消费者和提供者的方式实现一个消费者使用多个context中的数据

使用createConext,如何修改context的值

class App extends React.Component {
  constructor(){
    this.state = {
     info:''
    }
  }
  
  render() {
    const {signedInUser, theme} = this.props;

    // 提供初始 context 值的 App 组件
    return (
      <ThemeContext.Provider value={{
         info:this.state.info,
         changeInfo:(value)=>{this.setState({info:value}))
      
      }}>
        <UserContext.Provider value={signedInUser}>
          <Layout />
        </UserContext.Provider>
      </ThemeContext.Provider>
    );
  }
}

想要修改获取context的数据,只需要利用state和setState即可,然后在consumer中调用changeInfo方法即可。

使用useContext代替consumer,是子组件能够访问到context数据

function Counter(){
	const count = useContext(CountContext) //得到count
	return (<h2>{count}</h2>)
}

const CountContext = createContext()

function App(){
    const [ count , setCount ] = useState(0);

    return (
        <div>
            <p>你点击了{count} 次</p>
            <button onClick={()=>{setCount(count+1)}}>点击</button>
            <CountContext.Provider value={count}>
            	{/*======引入子组件*/}
            	<Counter />
            </CountContext.Provider>
        </div>
    )
}
export default App;