Sandeep Bisht
Sandeep Bisht

Reputation: 146

useSelector is unable to fetch latest value of state after re-render and return null

I am building a user page, in which i am getting user info from state itself using useState hook of redux.

import React, { useState, useEffect } from "react";
import profileImage from "../../resources/images/defaultProfile.png";
import { useSelector, useDispatch } from "react-redux";
import { userActions } from "../../state/actions";

const User = () => {
  const [isEditable, setIsEditable] = useState(false);

  const onChange = (e) => {
    setUser({
      ...user,
      [e.target.name]: [e.target.value],
    });
  };
  const onSubmit = () => {
    if (!isEditable) {
      setIsEditable(!isEditable);
    } else {
      //TODO update user data here
    }
  };
  const [user, setUser] = useState(useSelector((state) => state.user.user));

  return (
    user !== null && (
      <div className="container-fluid">
        <div className="row">
          <div className="col-md-9 border border-primary">user preference</div>
          <div className="col-md-3 border border-primary">
            <div className="row-cols-md-3 text-center">
              <img
                src={profileImage}
                alt="Profile image"
                style={{ width: "60%", height: "70%" }}
                className="border rounded-circle"
              />

              <form onSubmit={onSubmit} style={{ width: "100%" }}>
                <div className="mb-3">
                  <label htmlFor="userName" className="form-label">
                    User Name
                  </label>
                  <input
                    type="text"
                    name="name"
                    id="userName"
                    value={user.name}
                    onChange={onChange}
                    disabled={!isEditable ? "disabled" : ""}
                    className="form-control"
                  />
                </div>
                <div className="mb-3">
                  <label htmlFor="userEmail" className="form-label">
                    User Email
                  </label>
                  <input
                    type="email"
                    name="email"
                    disabled={!isEditable ? "disabled" : ""}
                    id="userEmail"
                    value={user.email}
                    onChange={onChange}
                    className="form-control"
                  />
                </div>
                <div className="mb-3">
                  <label htmlFor="userPhone" className="form-label">
                    User Phone Number
                  </label>
                  <input
                    type="text"
                    disabled={!isEditable ? "disabled" : ""}
                    name="phoneno"
                    id="userPhone"
                    value={user.phoneno}
                    onChange={onChange}
                    className="form-control"
                  />
                </div>

                <button type="submit">{isEditable ? "Update" : "Edit"}</button>
              </form>
            </div>
          </div>
        </div>
      </div>
    )
  );
};

export default User;

The data is loading fine for the first time. As shown initially all my input field are disabled but once i click on edit, it changes state isEditable and enables every field and change the submit button to "update" .It's re-render the page once the state isEditable is changed. I am loading navbar by default for every page and navBar has code which reloads the value of user state in case of refresh and once the page re-renders it reloads the user global state but somehow useSelector is unable to get latest value and just returns the null value.

Observation - once the complete re-renders happen useSelector is unable to fetch latest user data although the state has the latest value.

Can somebody please suggest what approach should i choose to overcome the following scenerio.

Upvotes: 0

Views: 1237

Answers (2)

Sandeep Bisht
Sandeep Bisht

Reputation: 146

Well i was surfing internet for the following issue and i found this. https://dmitripavlutin.com/react-forms-tutorial/ " By default, when clicking the form’s Submit button, the browser performs a full-page POST request to the URL specified in the action attribute of the . But having the form controlled by React, you can prevent browser’s default behavior by attaching an event handler to onSubmit event and calling event.preventDefault(). "

And based on this i bring my button out of the form, since now no complete post request would be called and hence it started working.

Frankly i am still not sure, earlier why it was working fine after second click.

Upvotes: 0

phry
phry

Reputation: 44364

Never do useState(useSelector(...));

It does not do what you expect.

useState is initialized once with the argument you put into it - so at first render, it will "capture" the value the selector returns at that point in time. But it will never update the state once the return value from useSelector changes. The local state is initialized after all.

Upvotes: 1

Related Questions