react functional component not re-rendered

Asked 2 years ago, Updated 2 years ago, 124 views

Re-render does not run when I call setState using react hooks.
Why is that?
When I press delete in todo app, the state value seems to have been updated, but redrawing does not run.
The state should have been updated with an array.
Here's the code.

//app.txs
constApp=()=>{
const [todo, setTodo] = React.useState<String[]>([])
// data storage
function handleAdd(e:any){
    e.preventDefault()
    setTodo(todo.concat(e.target.title.value))
    e.target.title.value=""
}
// data deletion
commandRemove=(i:number)=>{
    // Exclude first to i data in todo array
    todo.splice(i,1)
    setTodo (todo)
    console.log(todo)
}
return(
    <div>
        <h1>React Todo App</h1>
        <Form handleAdd={handleAdd}/>
        <div></div>
        <List todos={todo} handleRemove={handleRemove}/>
    </div>
)
}
ReactDOM.render(<App/>, document.getElementById("app"))


// List.tsx
const List=(props:any)=>{
return(
<ul>
    {props.todos.map(v:any, i:any)=>{
        return<li key={i}>{v}<span style={{cursor:"pointer"}} onClick={()=>{props.handleRemove(i)}}>delete</span><</li>
    })}
</ul>
)}
export default list

reactjs

2022-09-30 21:43

2 Answers

UseStatehook avoids rendering children when updated with the same value.The "same value" here means Object.is (old state, new state) is true.

Source: https://ja.reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update

Avoiding state updates

If the update is made with the same value as the current value, React avoids child renders or side effects and terminates the process (React uses comparison algorithm by Object.is).

If you look at the attached code, Object.is compares true because todo directly changes todo and passes the same todo array instance to setTodo.

Here's one solution.

consthandleRemove=(i:number)=>{
    // Copy todo to create a new Array instance.
    const newTodo = [...todo];
    // where Object.is(todo, newTodo) === false.
    // // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/is

    // Exclude the first data from the i-th in the newTodo array
    newTodo.splice(i,1);

    setTo (newTo);
}

Or you can write as follows:

consthandleRemove=(i:number)=>{
    setTodo([...todo.slice(0,i),...todo.slice(i+1)]);
}

The concat used in the handleAdd returns a new Array instance, so the child is always rendered. If you change it directly using push, it will not be re-rendered.

// Example not redrawn
consthandleAdd=(e)=>{
    e.preventDefault();
    todo.push(e.target.title.value);
    setTodo(todo);
    console.log(todo); // Output `todo` with new element added
    e.target.title.value="";
};


2022-09-30 21:43

They say they use immutability-helper to change the state array.


2022-09-30 21:43

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.