Wiktor Maciążek
Wiktor Maciążek

Reputation: 13

Why component in react dont re-rendering

Hello why component in react was not rendering? State was updated and i see it in developer tools but content was not changing

FULL CODE: https://pastebin.com/bxNUAieV

import React, {useState} from 'react'

const List = (props:any) => {
    const [actToDo, changeActTodo] = useState(props.actToDo)
    const [ToDoLists, changeActToDoLists] = useState(props.ToDoLists)
    return (
        <>
            {ToDoLists[actToDo].list.map((e:any, index:any) => (
            <div className={'Todo__element'}>
                <li key={index}>{e}</li><i className="fas fa-check"></i><i className="fas fa-recycle" onClick={() => props.removeElement(index)}></i>
            </div>))}
        </>
    )
}

export default List

ToDoLists[number].list save the list actToDo save number

const removeElement = (index:any) => {
    console.log(index);
    let FullList = ToDoLists
    //@ts-ignore
    FullList[actToDo].list.splice(index,1)
    changeToDoLists(FullList)
    console.log(ToDoLists);
}

Upvotes: 0

Views: 115

Answers (3)

Himanshu Singh
Himanshu Singh

Reputation: 1953

This is happening because, you are directly trying to update the same state array.

React compares the previous state with the updated state to decide if the component needs to be re-rendered. Modifying the state directly will disturb this process.


While updating:

Since you are updating the data inplace using splice at the previous state's address i.e. mutating the same array and the updating state, and the state TodoLists is a complex object (nested array), so, React cant track the update and thus not detecting the state change.

While creating new item

This is not happening at the time of new item creation as you are not directly appending/ mutating the old state, therefore, the state got updating and react detects state change.

For removing the items, you can do is

const removeElement = (index) => {
    console.log(index);
    let FullList = [...ToDoLists]; //<-- create copy of the list
    //@ts-ignore
    FullList[actToDo].list = [...FullList[actToDo]].list.filter( //<-- filter the list by removing toBeRemoved Object
      (_, i) => i !== index
    );
    console.log(FullList[actToDo]); 
    changeToDoLists(FullList); //update the state
};

Note: Whi;e updating a complex object, always keep in mind to use ... operator, which creates a shallow copy of your object for updating. It works both for array and object.

Upvotes: 0

lokeshj
lokeshj

Reputation: 938

What I can see in your code is that you are directly modifying a state variable, which we should never do in React. To modify a state variable first make its copy in a new variable, and after making changes , pass that new variable in setState function :

So instead of :

let FullList = ToDoLists

do like this :

let FullList = _.cloneDeep(objects);  //(using Lodash deep clone method here)
changeToDoLists(FullList);

Also , if you want to console your new list, then you should use useContext hook, since useState acts asynchronously and will not update value immediately, so console on very next line will not give updated value :

useEffect(() => {
  console.log('Here is my new list after updation', ToDoLists);
  }, [ToDoLists]);

Upvotes: 0

TheWuif
TheWuif

Reputation: 1036

you are mutating the array, that will not work, also the console.log will display the wrong value as setState is async.

https://dev.to/il3ven/common-error-accidentally-mutating-state-in-react-4ndg

const removeElement = (index:any) => {
    console.log(index);
    let FullList = { 
       ...ToDoLists,
       [actToDo]: {
          ...ToDoLists[actToDo],
          list: ToDoLists[actToDo].list.splice(index,1)
       }
    }
    console.log(FullList);
    changeToDoLists(FullList);
}

by the way, saving props to state is a bad behavior, as if the prop change nothing will happen.

Upvotes: 1

Related Questions