美文网首页
使用React Context进行状态管理(三)封装共享状态(变

使用React Context进行状态管理(三)封装共享状态(变

作者: du1dume | 来源:发表于2019-05-06 06:39 被阅读0次

    上次说到,我们其实可以把共享的东西封装成一个组件,这样可以让我们的代码结构更加清晰。怎么做呢?在之前创建的UserContext.js文件中,创建并导出了一个Context,用的React.createContext函数,现在我们不需要这个Context了,我们把这个Context直接解构成两个组件,Provider和Consumer。然后创建一个名为UserProvider的组件,在render函数中,我们return一个Provider组件,Provider组件的子组件为Provider组件所有的属性。代码如下:

    const { Provider, Consumer } = React.createContext();
    
    class UserProvider extends React.Component {
        render() {
            return (
                <Provider>{this.props.children}</Provider>
            )
        }
    }
    

    然后把App组件中UserContext.Provider的属性值剪切到Provider组件中来。代码如下:

    <Provider value={
            {
                user: this.state.user,
                onLogin: this.loginHandler,
                onLogout: this.logoutHandler
            }
    }>
    

    把App组件中的共享变量也剪切到这里来。完整代码如下:

    import React from 'react';
    import { User } from './helper'
    
    const { Provider, Consumer } = React.createContext();
    
    class UserProvider extends React.Component {
        state = {
            user: User,
        }
    
        loginHandler = user => {
            this.setState({ user: user })
        }
    
        logoutHandler = () => {
            this.setState({ user: null })
        }
    
        render() {
            return (
                <Provider value={
                    {
                        user: this.state.user,
                        onLogin: this.loginHandler,
                        onLogout: this.logoutHandler
                    }
                }>
                    {this.props.children}
                </Provider>
            )
        }
    }
    
    export { UserProvider, Consumer as UserConsumer }
    

    我们看到导出了两个对象,一个自定义的UserProvider组件,一个createContext解构来的Consumer组件,重命名为UserConsumer。

    首先修改App组件,导入新创建的组件,把老的UserContext.Provider替换为UserProvider,由于App组件里已经没有了this.state.user,我们就要用UserConsumer组件来使用共享user变量。代码如下:

    return (
                <UserProvider>
                    <UserConsumer>
                        {
                            ({ user }) =>
                                user
                                    ?
                                    (<Main />)
                                    :
                                    (<Login />)
                        }
                    </UserConsumer>
                </UserProvider>
            )
    

    类似的,修改Login组件,代码如下:

    <UserConsumer>
        {
            ({ onLogin }) => (
                <div>
                    <form onSubmit={e => submitHandler(e, onLogin)}>
                        <label>
                            用户名
                            <input
                                name="username"
                                value={username}
                                onChange={inputChangeHandler}
                                />
                        </label>
                        <label>
                            密码
                            <input
                                name="password"
                                type="password"
                                value={password}
                                onChange={inputChangeHandler}
                                />
                        </label>
                        {error && <div>{error.message}</div>}
                        <button type="submit" disabled={loading}>登录</button>
                    </form>
                </div>
            )
        }
    </UserConsumer>
    

    修改MessageList组件,代码如下:

    <UserConsumer>
        {
            ({ user }) => (
                <div>
                    <div>
                        没有邮件, {user.name}
                    </div>
                </div>
            )
        }
    </UserConsumer>
    

    修改Menu组件,代码如下:

    <UserConsumer>
        {
            ({ user, onLogout }) => (
                <div>
                    <img
                        src={user.avatar}
                        onClick={this.toggleMenu}
                        ref={this.avatarRef}
                        />
                    {this.state.visible && (
                        <ul>
                            <li onClick={onLogout}>退出登录</li>
                        </ul>
                    )}
                </div>
            )
        }
    </UserConsumer>
    

    修改完毕,运行程序发现和之前没什么两样,但我们的代码结构变得更加清晰了。譬如App组件,已经没有了任何关于状态和回调函数的代码,完全可以写成函数形式的组件了。

    下一回我们要讲一讲在同一个应用中使用多个Context Provider。

    相关文章

      网友评论

          本文标题:使用React Context进行状态管理(三)封装共享状态(变

          本文链接:https://www.haomeiwen.com/subject/nyjloqtx.html