最近,我在玩 React 并陷入了困境 - 在我看来,这是一个相当奇怪的问题。
import React, { useState } from "react";
import Person from "./Person";
import Filter from "./Filter";
function People(props) {
const [people, setPeople] = useState(props.people);
function filterPeople(name) {
let people = people.filter((person) =>
person.name.toLowerCase().startsWith(name.toLowerCase())
);
setPeople(people);
}
return (
<div>
<Filter filter={filterPeople} />
{people.map((person, id) => (
<Person key={id} person={person} />
))}
</div>
);
}
export default People;
在上面的代码中,我尝试从 prop people 设置状态 people(第 6 行),但它总是将其设置为空数组,即使我从父级传递的 people 属性不为空。更奇怪的是,当我console.log(props.people)时,它显示了正确的数据(这是一个3元素的数组)!如果有人可以解释我的实施情况,那将非常有帮助。
根据对该问题的评论,您似乎处于“重复状态”。也就是说,父组件维护 people
的状态,而该
People
组件 也维护
people
的状态。 这意味着当 props 更改时,该组件仍将使用其自己的本地状态。
没有额外的上下文...不要这样做。如果目标是使用 props 中传递的任何内容,只需使用它:
function People(props) {
function filterPeople(name) {
const filteredPeople = people.filter((person) =>
person.name.toLowerCase().startsWith(name.toLowerCase())
);
props.setPeople(filteredPeople);
}
return (
<div>
<Filter filter={filterPeople} />
{people.map((person, id) => (
<Person key={id} person={person} />
))}
</div>
);
}
这不仅需要传递
people
作为道具,还需要
setPeople
。
仍然没有上下文,但是也许您不想实际更新父组件的状态,而是只想在本地“过滤”此组件中的people
数组。在这种情况下,您可以跟踪状态中的
name
值并直接在渲染中进行过滤。例如:function People(props) {
const [name, setName] = useState('');
const filteredPeople = people.filter((person) =>
person.name.toLowerCase().startsWith(name.toLowerCase())
);
return (
<div>
<Filter filter={setName} />
{filteredPeople.map((person, id) => (
<Person key={id} person={person} />
))}
</div>
);
}
在大多数情况下,这不会带来足够大的性能损失,值得担心,但如果确实如此,你也可以记住
filteredPeople
:
function People(props) {
const [name, setName] = useState('');
const filterPeople = useMemo(() => {
return people.filter((person) =>
person.name.toLowerCase().startsWith(name.toLowerCase())
);
}, [people, name]);
const filteredPeople = filterPeople();
return (
<div>
<Filter filter={setName} />
{filteredPeople.map((person, id) => (
<Person key={id} person={person} />
))}
</div>
);
}
如果您计划稍后在原始状态的本地化副本上执行进一步操作而不修改父状态,则您可以保持状态重复。在这种情况下,如果您想在 prop 更改时更新本地状态,您可以使用 useEffect
:
来实现
function People(props) {
const [people, setPeople] = useState(props.people);
useEffect(() => {
setPeople(props.people);
}, [props.people]);
function filterPeople(name) {
let people = people.filter((person) =>
person.name.toLowerCase().startsWith(name.toLowerCase())
);
setPeople(people);
}
return (
<div>
<Filter filter={filterPeople} />
{people.map((person, id) => (
<Person key={id} person={person} />
))}
</div>
);
}
每当父组件为
props.people
发送不同的值时,这都会有效地覆盖对本地状态所做的任何更改。