Hasan Zubairi
Hasan Zubairi

Reputation: 1183

React useEffect not rerendering

I am trying to change a value in an array and rerender the component with useEffect but useEffect is not triggering. Value is being changed but calling useState has no effect.

const handleOptionClick = (e) => {

            var el = document.getElementById(e.currentTarget.id);
            var tar = el.getAttribute("data");
            
            var ans = awnsers;
            ans.map((res) => {
                if (res.Awnser === tar) {
                  res.IsChecked = !res.IsChecked;
                  return true;
                }
                return true;
              });
              setAwnsers(ans);
     }

and

useEffect(() => {
        console.log(awnsers);
    },[awnsers])

Upvotes: 1

Views: 2121

Answers (3)

Shubham Khatri
Shubham Khatri

Reputation: 281774

React performs an Object.is comparison while updating state and if the reference of previous and current state is same the check fails and a re-render is not triggered

Also map returns a new reference of the array and you must not mutate the original array but update it in an immutable manner

const handleOptionClick = (e) => {

        var el = document.getElementById(e.currentTarget.id);
        var tar = el.getAttribute("data");
        
        var ans = awnsers; // Check for typo
        ans = ans.map((res) => {
            if (res.Awnser === tar) {
              {...res, IsChecked:!res.IsChecked};
            }
            return res;
          });
          setAwnsers(ans);
 }

P.S. You can also make use of functional setState approach to update state since you are updating current state based on previous values

  const handleOptionClick = (e) => {

        var el = document.getElementById(e.currentTarget.id);
        var tar = el.getAttribute("data");
        setAwnsers(prevAns => ans.map((res) => {
            if (res.Awnser === tar) {
              {...res, IsChecked:!res.IsChecked};
            }
            return res;
        }));
 }

Upvotes: 0

Drew Reese
Drew Reese

Reputation: 202874

You don't save the result of the array::map function that you save in state, so essentially the state reference values in the awnsers array don't change and the component won't re-render.

const handleOptionClick = (e) => {
  var el = document.getElementById(e.currentTarget.id);
  var tar = el.getAttribute("data");
        
  setAwnsers(prevAwnser => prevAwnser.map(res => ({
    ...res,
    IsChecked: res.Awnser === tar ? !res.IsChecked : res.IsChecked,
  })));
}

Upvotes: 0

MjZac
MjZac

Reputation: 3526

Since you are doing a map on ans, I take it to be an array. Arrays are copied by reference. So for react to re-render the awnsers, you will have to create a new array.

var ans = [...awnsers]; // or JSON.parse(JSON.stringify(awnsers)) for deep clone
            ans.map((res) => {
                if (res.Awnser === tar) {
                  res.IsChecked = !res.IsChecked;
                  return true;
                }
                return true;
              });
              setAwnsers(ans);

Also is Awnsers a typo? Did you mean Answers?

Upvotes: 1

Related Questions