问题
I am currently playing around with the new React Hooks feature, and I have run into an issue where the state of a functional component is not being updated even though I believe I am doing everything correctly, another pair of eyes on this test app would be much appreciated.
import React, { useState, useEffect } from 'react';
const TodoList = () => {
let updatedList = useTodoListState({
title: "task3", completed: false
});
const renderList = () => {
return (
<div>
{
updatedList.map((item) => {
<React.Fragment key={item.title}>
<p>{item.title}</p>
</React.Fragment>
})
}
</div>
)
}
return renderList();
}
function useTodoListState(state) {
const [list, updateList] = useState([
{ title: "task1", completed: false },
{ title: "task2", completed: false }
]);
useEffect(() => {
updateList([...list, state]);
})
return list;
}
export default TodoList;
updateList in useTodoListState's useEffect function should be updating the list variable to hold three pieces of data, however, that is not the case.
回答1:
You have a few problems here:
- In
renderList
you are misusingReact.Fragment
. It should be used to wrap multiple DOM nodes so that the component only returns a single node. You are wrapping individual paragraph elements each in their own Fragment. - Something needs to be returned on each iteration of a
map
. This means you need to use thereturn
keyword. (See this question for more about arrow function syntax.) - Your code will update infinitely because
useEffect
is updating its own hook's state. To remedy this, you need to include an array as a second argument inuseEffect
that will tell React to only use that effect if the given array changes.
Here's what it should all look like (with some reformatting):
import React, { useState, useEffect } from 'react';
const TodoList = () => {
let updatedList = useTodoListState({
title: "task3", completed: false
});
return (
<React.Fragment> // #1: use React.Fragment to wrap multiple nodes
{
updatedList.map((item) => {
return <p key={item.title}>{item.title}</p> // #2: return keyword inside map with braces
})
}
</React.Fragment>
)
}
function useTodoListState(state) {
const [list, updateList] = useState([
{ title: "task1", completed: false },
{ title: "task2", completed: false }
]);
useEffect(() => {
updateList([...list, state]);
}, [...list]) // #3: include a second argument to limit the effect
return list;
}
export default TodoList;
Edit:
Although I have tested that the above code works, it would ultimately be best to rework the structure to remove updateList
from useEffect
or implement another variable to control updating.
来源:https://stackoverflow.com/questions/54974093/state-is-not-being-updated-when-using-react-hooks