1

I've followed a few online examples, where they have a counter and an increment function in Context, and on a distant component, call the increment method and the results shows. All great, but ... I am trying to expand on this and create a login box, that sets an isAthenticated flag.

I have a very basic context:

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;

In it I allow the user to change email, and change isAuthenticated state.

My component (Remove style stuff) looks like this:

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;

So when I change the email, the Context state is updated. And when I click the Login button, for now, it simply toggles IsAuthenticated.

I don't want the state to update as I type in the email box. I'd prefer to update the state when the Login button is clicked. So I feel I need a local component state, or something, which updates that state when I edit the data in the text boxes. And then updates the Context when I click Login.

But... How do I set up the state? 'values' (from context) is only available inside the Render. I need to set my component state outside of the render. So how would I go about achieving this?

My login button onClick should also fire a local method which has all the validation etc, and then update my route to redirect to a page on success. But then it needs access to the Context.UpdateMethod - from outside of the tags. Not sure how to achieve this.

Craig
  • 15,856
  • 29
  • 129
  • 224
  • From your question it seems that, the only problem you face is to use context outside of render which the duplicate post covers in detail. Let me know if it still doesn't work for you – Shubham Khatri Jun 14 '19 at 05:33

1 Answers1

1

You should probably just create a sub-component and then use the props to initialize the state.

class Login extends React.Component {
  render() {
    return (
      <Consumer>
        {value => (
          <Container style={containerStyle}>
            <SubComponent
              changeAuthenticated={value.changeAuthenticated}
              // ...etc
Austin Greco
  • 29,311
  • 5
  • 50
  • 55