0

Once button clicked the fields are validated and errors are assigned to state variable.

But when state is updated inside onSubmitClick the render/view isn't refreshed to show the errors.

I have cross checked TextField component by doing a log of error fields but error doesn't seem to show up..

import React, { useState } from "react";

const Register = () => {
  const [user, setUser] = useState({
    name: "",
    email: "",
    password: "",
  });

  const setData = (type) => e => {
    user[type] = e.target.value;
    setUser(user);
  };

  const onSubmitClick = e => {
    // Check if fields are empty
    if (!user.name) {
      user.nameError = "Name field cannot be left blank !!";
    }

    if (!user.email) {
      user.emailError = "Email field cannot be left blank !!";
    }

    if (!user.password) {
      user.passwordError = "Password field cannot be left blank !!";
    }

    // Setting the error here
    setUser(user);
  };

  return (
    <div>
      <TextField value={user.name} error={user.nameError} label="Name" onChange={setData("name")} />
      <TextField value={user.email} error={user.emailError} label="Email" onChange={setData("email")} />
      <TextField value={user.password} error={user.passwordError} abel="Password" onChange={setData("password")} />
      <Button content="REGISTER" onClick={onSubmitClick} />
    </div>
  );
};

export default Register;

So basically on submit if fields have errors i need to show up the errors.

3 Answers 3

2

You are mutating the user state object and setting the state with the same object reference, this is why the component is not re-rendering it is a good practice to always construct a new object from the current state before updating the state.

const setData = (type) => e => {
  setUser(prevState => ({
    ...prevState,
    [type]: e.target.value,
  }));
};

const onSubmitClick = e => {
  // destruct the current state and make a new object of it
  // now we can mutate it and assign it to state
  const updatedState = { ...user };
  // Check if fields are empty
  if (!updatedState.name) {
    updatedState.nameError = "Name field cannot be left blank !!";
  }

  if (!updatedState.email) {
    updatedState.emailError = "Email field cannot be left blank !!";
  }

  if (!updatedState.password) {
    updatedState.passwordError = "Password field cannot be left blank !!";
  }

  setUser(updatedState);
};
Sign up to request clarification or add additional context in comments.

Comments

1

I dont understand why u need to send extra type you can do it simply by fetching name from input box. And in your case, you are not setting right state in setData i.e its not mutating userData. You can do like this : In your case you can do like this :

    setUser({...user,user[type] : e.target.value}); // ensure rest value will remain there and update existing value

import React, { useState } from "react";
import { render } from 'react-dom';



const Register = () => {
  const [user, setUser] = useState({
    name: "",
    email: "",
    password: "",
  });

  const setData =  e => {
    console.log(e.target.name)

    console.log(user)
    setUser({...user,[e.target.name] : e.target.value});
  };

  const onSubmitClick = e => {
    // Check if fields are empty
    if (!user.name) {
      user.nameError = "Name field cannot be left blank !!";
    }

    if (!user.email) {
      user.emailError = "Email field cannot be left blank !!";
    }

    if (!user.password) {
      user.passwordError = "Password field cannot be left blank !!";
    }
  console.log(user)
    // Setting the error here
    setUser(user);
  };

  return (
    <div>
      <input value={user.name} error={user.nameError} name="name" label="Name" onChange={(e) => setData(e)} />
      <input value={user.email} error={user.emailError} name="email" label="Email" onChange={(e) => setData(e)} />
      <input value={user.password} error={user.passwordError} name="password" label="Password" onChange={(e) => setData(e)} />
      <button content="REGISTER" onClick={onSubmitClick} >Submit</button>
    </div>
  );
};

export default Register;


render(<Register />, document.getElementById('root'));

Here is working link : https://stackblitz.com/edit/react-fbuzph

Comments

1

You are making updates to the same state object in reference instead of creating a new state altogether. React only re-renders your component through either receiving new props or a new state object.

See sandbox and code-below on how to add and clear errors onSubmit: https://codesandbox.io/s/blissful-river-ou4o0

Register.js

import React, { useState } from "react";
import ReactDOM from "react-dom";
import TextField from "./TextField";

import "./styles.css";

const Register = () => {
  const [user, setUser] = useState({
    name: "",
    email: "",
    password: ""
  });

  const setData = e => {
    const updatedUser = { ...user };

    updatedUser[e.target.name] = e.target.value;
    setUser(updatedUser);
  };

  const onSubmitClick = e => {
    // Check if fields are empty
    const updatedUser = { ...user };

    updatedUser.nameError = !updatedUser.name
      ? "Name field cannot be left blank !!"
      : "";

    updatedUser.emailError = !updatedUser.email
      ? "Email field cannot be left blank !!"
      : "";

    updatedUser.passwordError = !updatedUser.password
      ? "Password field cannot be left blank !!"
      : "";

    setUser(updatedUser);
  };

  return (
    <div>
      <TextField
        value={user.name}
        error={user.nameError}
        name="name"
        label="Name"
        onChange={setData}
      />
      <TextField
        value={user.email}
        error={user.emailError}
        name="email"
        label="Email"
        onChange={setData}
      />
      <TextField
        value={user.password}
        error={user.passwordError}
        name="password"
        label="Password"
        onChange={setData}
      />
      <button content="REGISTER" onClick={onSubmitClick}>
        Submit
      </button>
    </div>
  );
};

export default Register;

const rootElement = document.getElementById("root");
ReactDOM.render(<Register />, rootElement);

TextField.js

import React from "react";

const TextField = props => {
  return (
    <div>
      <label>{props.label}</label>
      <input value={props.value} name={props.name} onChange={props.onChange} />
      {props.error ? <p>{props.error}</p> : null}
    </div>
  );
};

export default TextField;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.