Based on comments on the question, you appear to be duplicating state. That is, the parent component maintains people
in state, and this People
component also maintains people
in state.
Which means that when the props change, this component will still be using its own local state.
Without additional context... don't do that. If the goal is to use whatever is passed in props, just use that:
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>
);
}
This would require not only passing people
as a prop, but also setPeople
.
Alternatively: Still without context, but maybe you don't want to actually update the parent component's state but instead want to only locally "filter" the people
array in this component. In that case you could track that name
value in state and filter directly in the rendering. For example:
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>
);
}
In most cases this won't incur a significant enough performance penalty to worry about, but if it does then you can also memo-ize 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>
);
}
Alternatively: You could keep state duplicated if you plan to perform further operations at a later time on a localized copy of the original state without modifying the parent state. In that case if you want to update the local state any time the prop changes, you can do that with 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>
);
}
This would effectively over-write whatever changes have been made to local state any time the parent component sends a different value for props.people
.