为什么React Context仅触发DOM元素传递的值函数

时间:2019-06-15 17:55:56

标签: javascript reactjs

我正在尝试使用React Context更新我的Web应用程序的登录/注销功能。由于这不是一个高流量函数,因此我认为这是使用上下文API,创建我的提供程序并利用链中必要组件中的提供程序的绝佳机会。

不幸的是,看来我无法在组件函数中使用任何传递的函数,例如handleSubmit()。如果我直接从DOM元素中调用它们(它们在下面的示例中),它们的效果很好。

我认为这是某种“ this”错误,并且DOM调用使用的范围与组件中使用的范围不同。

任何有关为什么发生这种情况以及如何解决它的帮助都将非常有用。

谢谢!

上下文:

export const LoginContext = React.createContext({});
export class LoginCtx extends Component {
    constructor(props) {
        super(props);
        this.state = {
            isLoggedIn: false,
            login: () => this.login,
            logout: () => this.logout
        };
        this.login = this.login.bind(this);
        this.logout = this.logout.bind(this);
    }

    login(user) {
        console.log('Inside Login:', user);
        this.setState({ isLoggedIn: true });
    }

    logout() {
        console.log('Inside Logout');
        this.setState({ isLoggedIn: false });
    }

    render() {
        return (
            <LoginContext.Provider value={this.state}>
                {this.props.children}
            </LoginContext.Provider>
        );
    }
}

表格:

const C = ({ classes }) => {
    const { login } = useContext(LoginContext);

    const initialValues = {
        email: 'abc@test.com',
        password: '',
        remember: false
    };

    const dummySubmit = async (values, actions) => {
        console.log(JSON.stringify(values, null, 2));
        if (values.email === 'abc@test.com') {

            // THIS ONE WONT FIRE THE LOGIN COMMAND
            login();
        }
        actions.setSubmitting(false);
    };

    return (
        <React.Fragment>
            <Formik
                initialValues={initialValues}
                onSubmit={(values, actions) => dummySubmit(values, actions)}
            >
                {({ isSubmitting }) => (
                    <Form className={classes.form}>
                        <div>
                            <Field
                                name='email'
                                type='email'
                                placeholder='Email'
                            />
                            <ErrorMessage name='email' component='div' />
                        </div>
                        <div>
                            <Field
                                name='password'
                                type='password'
                                placeholder='Password'
                            />
                            <ErrorMessage name='email' component='div' />
                        </div>
                        <button type='submit' disabled={isSubmitting}>
                            Login
                        </button>
                    </Form>
                )}
            </Formik>

            {/* THIS ONE DOES FIRE THE LOGIN COMMAND */}
            <button onClick={login()}>Login Ctx</button>
        </React.Fragment>
    );
};

1 个答案:

答案 0 :(得分:0)

this.state = {
    isLoggedIn: false,
    login: () => this.login,
    logout: () => this.logout
};

您在此处创建的函数除了返回对this.login / this.logout的引用外没有任何作用。就目前而言,位于组件树下方的组件必须调用从上下文中获取的函数,然后调用由第一次调用返回的函数。例如:

const { login } = useContext(LoginContext);
// ...
login()();

您很可能打算这样做:

this.state = {
    isLoggedIn: false,
    login: () => this.login(),
    logout: () => this.logout()
};
this.login = this.login.bind(this);
this.logout = this.logout.bind(this);

或者这个:

this.login = this.login.bind(this);
this.logout = this.logout.bind(this);
this.state = {
    isLoggedIn: false,
    login: this.login,
    logout: this.logout
};