likes
comments
collection
share

11-react-context上下文

作者站长头像
站长
· 阅读数 31

上下文

上下文(Context) 提供了一种通过组件树传递数据的方法,无需在每个级别手动传递 props 属性。非常之方便。

在典型的 React 应用程序中,数据通过 props 自上而下(父到子)传递,但对于应用程序中许多组件所需的某些类型的 props(例如环境偏好,UI主题),这可能很麻烦。 上下文(Context) 提供了在组件之间共享这些值的方法,而不必在树的每个层级显式传递一个 prop 。

何时用Context?

顶层数据改变,让下面所有的都改变,例如,点击按钮,使子组件的主题都进行交换。注意:不使用props传值。

在源码中,容器提供了proviser consumer,创建两个组件,且可以传入默认值以备用。

正文:

定义两个主题:

 const themes = {
            light: {
                color: "pink",
                background: "pink"
            },
            dark: {
                color: 'white',
                background: "white"
            }
        }

然后创建一个 { Provider, Consumer } 对。当 React 渲染 context Consumer 时,它将从组件树中匹配最接近的 Provider 中读取当前的 context 值。

defaultValue 参数  当 Consumer(使用者) 在树中没有匹配的 Provider(提供则) 时使用它。这有助于在不封装它们的情况下对组件进行测试。注意:将 undefined 作为 Provider(提供者) 值传递不会导致 Consumer(使用者) 使用 defaultValue 。

在这里,我们定义默认为粉色主题:

 const { Provider, Consumer } = React.createContext({ theme: themes.light })

先去定义一个根组件,在根组件中嵌套一个A作为子组件,B也作为子组件,但不同的是,一个会用于provider的使用,另一个不会。

render(){
    return(
        <A>A组件</A>
         <ThemeButton />
         <B/>
    )
}
 function ThemeButton() {
   return (
       <button>change theme<button/>
   )

当点击按钮时,进行主题切换。

方法,用到一个三元:

handleTheme = () => {
                const theme = this.state.theme === themes.light ? themes.dark : themes.light
                this.setState({
                    theme
                })
            }

定义好方法,就可以在provider中设置value了。

注意为什么在一个构造函数中,是因为在该构造函数中的方法,会等到非构造函数中的方法挂载完再运行,这样就避免了里面的方法是undefined的现象。

 constructor() {
                super();
                // 在这里能拿到箭头函数,在外面拿不到
                this.state = { theme: themes.light, handleTheme: this.handleTheme }
            }

下面,回到根组件中的provider中,传入value给consumer。

  render() {
                return (
                    <div>
                        <Provider value={this.state}>
                            <A >A 组件,我被包裹了</A>
                            <ThemeButton />
                        </Provider>
                        <B />
                    </div>
                )
            }

在上述代码中,包裹在provider中的组件才会被掌控,组件B的主题始终都会是默认值。

已经将值传给子组件,下面用Consumer来接收并使用:

通过一个回调的方式拿到对象,对象里包含balue传过来的所有数据,有主题和方法,可以拆解出来的。 另外要注意consumer只能是后面接{}的格式,不可以中间隔div,亲测报错。来到A组件中:

 function A() {
            return (
                <Consumer>
                    {
                        //拿到这个 通过函数传过来 值
                        (obj) => {
                            console.log(obj);
                            const {theme,handleTheme} = obj
                            return (
                                <div>
                                    <h1 style={{ ...theme }}>A Component,我被包裹了</h1>                               
                                </div>
                            )
                        }
                    }

                </Consumer>

            )
        }

再来到按钮组件中,同样的方法,回调解构取值

 function ThemeButton() {
            return (
                <Consumer>{
                    (obj) => {
                        const {theme,handleTheme} = obj
                        return (
                            <button onClick={handleTheme
                            } style={{ ...theme }} >change theme</button>
                        )

                    }
                }
                </Consumer>

            )
        }

11-react-context上下文

真的很方便吧。

多个context

为了保持 context 的快速重新渲染,React 需要使每个 context Consumer 成为树中的一个独立节点。

设置provider:

const MoneyContext = React.createContext(0)
const HouseContext = React.createContext("")
        class F extends React.Component {
            state = {
                money: 50,
                house: "apartment"
            }
            render() {
                return (
                    // 区分provider
                    <MoneyContext.Provider value={this.state.money}>
                        <HouseContext.Provider value={this.state.house}>
                            <S />
                        </HouseContext.Provider>
                    </MoneyContext.Provider>
                )
            }
        }

使用consumer:

   return (
                    <MoneyContext.Consumer>
                        {
                            (money) => {
                                return (
                                    <HouseContext.Consumer>
                                        {
                                            (house) => {
                                                return (
                                                    <div>
                                                        <p>{money}</p>
                                                        <p>{house}</p>
                                                    </div>
                                                )
                                            }
                                        }
                                    </HouseContext.Consumer>
                                )
                            }
                        }
                    </MoneyContext.Consumer>
                )

就完成数据的展示了!yeah.