skip to Main Content

I have a case here, which is to make a remember me function when logging in.

So, yesterday I got an online repo on codesandbox which contains reactjs component remember me.

Then I want to convert it into react hooks.

The code is like this (React Component original)

import React from "react";

class RememberMe extends React.Component {
  static displayName = "RememberMe";

  state = {
    email: "",
    password: "",
    isChecked: false
  };

  componentDidMount() {
    if (localStorage.checkbox && localStorage.email !== "") {
      this.setState({
        isChecked: true,
        email: localStorage.username,
        password: localStorage.password
      });
    }
  }

  onChangeValue = (event) => {
    this.setState({
      [event.target.name]: event.target.value
    });
  };

  onChangeCheckbox = (event) => {
    this.setState({
      isChecked: event.target.checked
    });
  };

  loginSubmit = () => {
    const { email, password, isChecked } = this.state;
    if (isChecked && email !== "") {
      localStorage.username = email;
      localStorage.password = password;
      localStorage.checkbox = isChecked;
    }
  };

  render() {
    const { email, password, isChecked } = this.state;
    return (
      <div>
        <form>
          <table align="center">
            <tr>
              <td>
                <label>Email</label>
              </td>
              <td>
                <input
                  type="email"
                  name="email"
                  value={email}
                  onChange={this.onChangeValue}
                />
              </td>
            </tr>
            <tr>
              <td>
                <label>Password</label>
              </td>
              <td>
                <input
                  type="password"
                  name="password"
                  value={password}
                  onChange={this.onChangeValue}
                />
              </td>
            </tr>
            <tr>
              <td colSpan="2">
                <input
                  type="checkbox"
                  checked={isChecked}
                  name="lsRememberMe"
                  onChange={this.onChangeCheckbox}
                />
                <label>Remember me</label>
              </td>
            </tr>
            <tr>
              <td colSpan="2">
                <input type="button" value="Login" onClick={this.loginSubmit} />
              </td>
            </tr>
          </table>
        </form>
      </div>
    );
  }
}

export default RememberMe;

However, when it was finished, I tried to convert it into hooks, but it didn’t work properly, I thought, "Is there something wrong in my code? Thank you

    import React, { useState, useEffect } from "react";
    
    const Me = () => {
      const [email, setEmail] = useState("");
      const [password, setPassword] = useState("");
      const [isChecked, setIsChecked] = useState(false);
    
      useEffect(() => {
        if (localStorage.checkbox && localStorage.email !== "") {
          setEmail({ email: localStorage.username });
          setPassword({ password: localStorage.password });
          setIsChecked({
            isChecked: true
          });
        }
      }, []);
    
      const onChangeValue = (event) => {
        setIsChecked({
          [event.target.name]: event.target.value
        });
      };
    
      const onChangeCheckbox = (event) => {
        setIsChecked({
          isChecked: event.target.checked
        });
      };
    
      const loginSubmit = () => {
        if (isChecked && email !== "") {
          localStorage.username = email;
          localStorage.password = password;
          localStorage.checkbox = isChecked;
        }
      };
    
      return (
        <div>
          <form>
            <table align="center">
              <tr>
                <td>
                  <label>Email</label>
                </td>
                <td>
                  <input
                    type="email"
                    name="email"
                    value={email}
                    onChange={onChangeValue}
                  />
                </td>
              </tr>
              <tr>
                <td>
                  <label>Password</label>
                </td>
                <td>
                  <input
                    type="password"
                    name="password"
                    value={password}
                    onChange={onChangeValue}
                  />
                </td>
              </tr>
              <tr>
                <td colSpan="2">
                  <input
                    type="checkbox"
                    checked={isChecked}
                    name="lsRememberMe"
                    onChange={onChangeCheckbox}
                  />
                  <label>Remember me</label>
                </td>
              </tr>
              <tr>
                <td colSpan="2">
                  <input type="button" value="Login" onClick={loginSubmit} />
                </td>
              </tr>
            </table>
          </form>
        </div>
      );
    };

export default Me;

https://codesandbox.io/s/remember-me-localstorage-forked-crpt1z

2

Answers


  1. Look closely at the types of your state.

    Unlike with a class component where there’s one state object with various keys, each state atom is now separate and should just hold the value itself, yet you’re setting objects into them, e.g.

    setEmail({ email: localStorage.username });
    

    Invocations like that should be just

    setEmail(localStorage.username);
    

    and so on.

    You also don’t need useEffect(); just use useState‘s function initialization:

    import React, { useState } from "react";
    
    function Me() {
      // State, initial state loaded from local storage if set
      const [email, setEmail] = useState(() => (localStorage.checkbox ? localStorage.username : ""));
      const [password, setPassword] = useState(() => (localStorage.checkbox ? localStorage.password : ""));
      const [isChecked, setIsChecked] = useState(() => !!localStorage.checkbox);
    
      const loginSubmit = () => {
        if (isChecked && email !== "") {
          localStorage.username = email;
          localStorage.password = password;
          localStorage.checkbox = isChecked ? "1" : "";
          alert("Okay!");
        }
      };
    
      return (
        <div>
          <form>
            <table align="center">
              <tr>
                <td>
                  <label>Email</label>
                </td>
                <td>
                  <input type="email" name="email" value={email} onChange={(e) => setEmail(e.target.value)} />
                </td>
              </tr>
              <tr>
                <td>
                  <label>Password</label>
                </td>
                <td>
                  <input type="password" name="password" value={password} onChange={(e) => setPassword(e.target.value)} />
                </td>
              </tr>
              <tr>
                <td colSpan="2">
                  <input
                    type="checkbox"
                    checked={isChecked}
                    name="lsRememberMe"
                    onChange={(e) => setIsChecked(e.target.checked)}
                  />
                  <label>Remember me</label>
                </td>
              </tr>
              <tr>
                <td colSpan="2">
                  <input type="button" value="Login" onClick={loginSubmit} />
                </td>
              </tr>
            </table>
          </form>
        </div>
      );
    }
    
    Login or Signup to reply.
  2. Yes, there’s a number of things wrong with your hooks code. Let’s go through a few of them in turn:

    1. if (localStorage.checkbox && localStorage.email !== "") {
      I notice that further down, you save the email like this localStorage.username = email. Why are you checking localStorage.email? Shouldn’t you be checking localStorage.username in your if statement instead?
    2. setEmail({ email: localStorage.username });
      Try doing this instead: setEmail(localStorage.username). You don’t need the wrapping object here. Same thing goes for the other two fields.
    3. This entire block doesn’t make sense – why are you only using setIsChecked but expecting the other values to be updated? You’ll need to create a different handler for each field accordingly.
    const onChangeValue = (event) => {
      setIsChecked({
        [event.target.name]: event.target.value
      });
    };
    
    1. onChange={onChangeValue} like point 3 above, you’ll need onChange={onChangeEmail} and onChange={onChangePassword} as separate handlers.

    Functionality aside, there’s a number of additional things to consider:

    • Accessibility. Read this page and consider changes accordingly: https://reactjs.org/docs/accessibility.html
    • DON’T store passwords in plain text in localStorage. You should be passing them to a backend auth API and receiving either cookies or a JWT token.

    If you make these changes you should get closer to a working project. Make sure you take the additional considerations into account before using your project anywhere in a real scenario!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search