使用两个不同的 useState 钩子来存储数组和过滤数组以传递给组件是否正确?
Is it correct to use two different useState hook to store an array and a filtered array for passing to components?
我目前正在将我的 Pokemon 项目移植到 React,因为几周前我刚刚学习了 React 的基础知识,想看看我能适应它的程度。现在,我构建代码的方式是使用两个不同的 useState 挂钩,一个用于从 PokeAPI 获取的原始数组,并且只设置一次。这个原始数组也被传递到我的表单 object 中,它根据一些表单元素(如 Pokemon 类型或 Pokemon 的名称)对其进行过滤。另一个 useState 挂钩用于跟踪 filteredList,它是使用 Array.map()
函数呈现给网站的内容。
const [pokemonList, setPokemonList] = useState([]);
const [filteredList, setPokemonFilteredList] = useState([]);
这是我们获取和设置状态的 useEffect()
挂钩
useEffect(() => {
const getPokemon = async () => {
const list = await fetchPokemon();
setPokemonList(list);
setPokemonFilteredList(list);
};
最后 pokemonList
状态变量和 setPokemonFilteredList
方法被传递到 <PokemonSearchForm>
<PokemonSearchForm pokemonList={pokemonList} setPokemonList={setPokemonFilteredList} />
那么正如我的问题标题所暗示的那样,我使用两种不同的方式 useState()
'correct' 吗?也许 child 组件访问 pokemonList 变量的另一种方式?但我相信这可能是一个 anti-pattern.
我会用几种不同的方式重构它:
- 在父组件中保留过滤器状态,子组件会在这些更改时简单地通知它。
- 为 useMemo 放弃
useState
,后者每次依赖项发生变化时都会计算一个值。
function YourComponent() {
const [filters, setFilters] = useState({});
const [pokemons, setPokemons] = useState([]);
useEffect(
() => {
const list = await fetchPokemon();
setPokemons(list);
},
[]
);
// This will run each time `filters` or `pokemons` change.
const filteredPokemons = useMemo(
() => {
return pokemons.filter((pokemon) => {
// Perform any filtering logic you may have,
// based on the filters set by the child component.
if (filters.name) {
return pokemon.name.includes(filters.name);
}
// etc...
});
},
[filters, pokemons]
);
return (
<PokemonSearchForm
pokemons={filteredPokemons}
onChange={setFilters}
/>
);
}
更好的做法是不保持重复状态,或者在这种情况下,派生状态,因为您可能运行进入分歧。例如,如果您的原始 pokemon 数据得到更新,您将如何确保过滤后的数据得到更新,然后重新应用过滤器?长毛的速度非常快。
首选的替代方法是在状态中维护原始数据和过滤器,然后在渲染期间计算派生状态(在这种情况下,过滤列表)。
function App() {
const [pokemonList, setPokemonList] = useState([]);
// Some default filter state
const [filters, setFilters] = useState({
types: ["any"],
search: ""
});
const filteredList = pokemonList.filter((pokemon) => {
// Filter logic here
});
return <PokemonSearchForm setFilters={setFilters} />
}
我目前正在将我的 Pokemon 项目移植到 React,因为几周前我刚刚学习了 React 的基础知识,想看看我能适应它的程度。现在,我构建代码的方式是使用两个不同的 useState 挂钩,一个用于从 PokeAPI 获取的原始数组,并且只设置一次。这个原始数组也被传递到我的表单 object 中,它根据一些表单元素(如 Pokemon 类型或 Pokemon 的名称)对其进行过滤。另一个 useState 挂钩用于跟踪 filteredList,它是使用 Array.map()
函数呈现给网站的内容。
const [pokemonList, setPokemonList] = useState([]);
const [filteredList, setPokemonFilteredList] = useState([]);
这是我们获取和设置状态的 useEffect()
挂钩
useEffect(() => {
const getPokemon = async () => {
const list = await fetchPokemon();
setPokemonList(list);
setPokemonFilteredList(list);
};
最后 pokemonList
状态变量和 setPokemonFilteredList
方法被传递到 <PokemonSearchForm>
<PokemonSearchForm pokemonList={pokemonList} setPokemonList={setPokemonFilteredList} />
那么正如我的问题标题所暗示的那样,我使用两种不同的方式 useState()
'correct' 吗?也许 child 组件访问 pokemonList 变量的另一种方式?但我相信这可能是一个 anti-pattern.
我会用几种不同的方式重构它:
- 在父组件中保留过滤器状态,子组件会在这些更改时简单地通知它。
- 为 useMemo 放弃
useState
,后者每次依赖项发生变化时都会计算一个值。
function YourComponent() {
const [filters, setFilters] = useState({});
const [pokemons, setPokemons] = useState([]);
useEffect(
() => {
const list = await fetchPokemon();
setPokemons(list);
},
[]
);
// This will run each time `filters` or `pokemons` change.
const filteredPokemons = useMemo(
() => {
return pokemons.filter((pokemon) => {
// Perform any filtering logic you may have,
// based on the filters set by the child component.
if (filters.name) {
return pokemon.name.includes(filters.name);
}
// etc...
});
},
[filters, pokemons]
);
return (
<PokemonSearchForm
pokemons={filteredPokemons}
onChange={setFilters}
/>
);
}
更好的做法是不保持重复状态,或者在这种情况下,派生状态,因为您可能运行进入分歧。例如,如果您的原始 pokemon 数据得到更新,您将如何确保过滤后的数据得到更新,然后重新应用过滤器?长毛的速度非常快。
首选的替代方法是在状态中维护原始数据和过滤器,然后在渲染期间计算派生状态(在这种情况下,过滤列表)。
function App() {
const [pokemonList, setPokemonList] = useState([]);
// Some default filter state
const [filters, setFilters] = useState({
types: ["any"],
search: ""
});
const filteredList = pokemonList.filter((pokemon) => {
// Filter logic here
});
return <PokemonSearchForm setFilters={setFilters} />
}