React Context API和组件方法

时间:2019-06-14 04:05:45

标签: javascript reactjs

我遵循了一些在线示例,这些示例在Context中具有一个计数器和一个递增函数,在一个遥远的组件上,调用递增方法并显示结果。一切都很好,但是...我正在尝试对此进行扩展,并创建一个设置isAthenticated标志的登录框。

我有一个非常基本的背景:

import React from 'react';

const Context = React.createContext();

export class Provider extends React.Component {

    state = {
        isAuthenticated: false,
        user: {
            name: "Craig",
            email: "craig@here.com"
        },
        changeEmail: (newEmail) => {
            let user = this.state.user;
            user.email = newEmail;
            console.log(user);
            this.setState({ user: user})
        },
        changeAuthenticated: () => {
            this.setState ({ isAuthenticated: !this.state.isAuthenticated });
        }
    }

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

export const Consumer = Context.Consumer;

在其中,我允许用户更改电子邮件并更改isAuthenticated状态。

我的组件(删除样式的东西)如下:

import React from 'react';
import { Input, Label, Button, Container } from 'reactstrap';
import { Consumer } from '../context';


class Login extends React.Component {

    render() {


        return (
            <Consumer>
                {value => {
                    return (
                        <Container style={containerStyle} >
                            <div style={loginBoxStyle}>
                                <div>
                                    <h3>Login</h3>
                                </div>
                                <div style={loginBoxFieldsStyle}>
                                    <div style={loginBoxFieldStyle}>
                                        <div style={loginBoxLabelStyle}>
                                        <Label for="email">Email:</Label>
                                        </div>
                                        <div style={loginBoxLabelStyle}>
                                            <Input type="email" name="email" id="email" placeholder="Your Email" value={value.user.email} onChange={e=>value.changeEmail(e.target.value)} />  
                                        </div>
                                    </div>
                                </div>
                                <div style={loginBoxFieldsStyle}>
                                    <div style={loginBoxFieldStyle}>
                                        <div style={loginBoxLabelStyle}>
                                            <Label for="password">Password:</Label>
                                        </div>
                                        <div style={loginBoxLabelStyle}>
                                        <Input type="password" name="password" id="password" placeholder="Your Password" />
                                        </div>
                                    </div>
                                </div>
                                <div style={loginBoxButtonStyle}>
                                    <Button color="info" onClick={value.changeAuthenticated}>Login</Button>
                                </div>
                            </div>
                        </Container>
                    )}
                }
            </Consumer>
        )
    }
}

export default Login;

因此,当我更改电子邮件时,上下文状态也会更新。现在,当我单击“登录”按钮时,它仅会切换IsAuthenticated。

我不希望在输入电子邮件时更新状态。我希望在单击“登录”按钮时更新状态。因此,我觉得我需要一个本地组件状态或其他某种状态,以便在编辑文本框中的数据时更新该状态。然后在单击“登录”时更新上下文。

但是...我该如何设置状态? “值”(来自上下文)仅在渲染器内部可用。我需要在渲染之外设置组件状态。那么我将如何实现这一目标?

我的登录按钮onClick也应触发具有所有验证等功能的本地方法,然后在成功时更新我的​​路由以重定向到页面。但是随后它需要从标记外部访问Context.UpdateMethod。不确定如何实现。

1 个答案:

答案 0 :(得分:0)

您可能应该只创建一个子组件,然后使用道具初始化状​​态。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        this.textBox1.Text = "Loading data...";

        LoadData();
    }

    private async void LoadData()
    {
        string text = null;

        await Task.Run(() =>
        {
            text = File.ReadAllText("z:\\very_large_file.txt");
        });

        this.textBox1.Text = text;
    }
}