我认为我的问题有一段时间似乎是重复的,但我想不是,我检查了许多标题相同但大小写不同的问题
问题是,我被迫在我的代码中使用了两次react hook,我甚至想让它们变成三次,但我觉得这是一个糟糕的做法,我相信有一个解决办法或的解决方案
我有我想最初获取的数据,我通过第一个useEffect调用实现了这一点,以后可以对数据进行过滤或排序,我有过滤器复选框和排序查询的选择,选中复选框将过滤数据,选择选项将对其进行排序,我使用redux和react reduconnect方法来创建状态树,其中包括过滤器和sortBy
//the first call
useEffect(() => {
loadProducts();
}, []);
//the second call
useEffect(() => {
loadProducts(filters, sortBy)
}, [filters, sortBy])
const mapStateToProps = (state) => ({
filters: state.filters,
sortBy: state.sortBy
});
const mapDispatchToProps = (dispatch) => ({
loadProducts: (filters, sortBy) => {
fetch('certain API').then(res => res.json()).then(json => {
dispatch(fetchProducts(json.products, filters, sortBy));
}).catch(err => 'error fetching data');
}
});
现在,第一个调用是最初从API检索数据,loadProducts函数不需要任何参数,第二个调用是在进行筛选或排序时,本例中的函数需要参数,当任何筛选器或sortBy更改时,它都会工作
我甚至想把第二个电话分成两个这样的电话,让他们打三个电话:
useEffect(() => {
loadProducts(filters)
}, [filters])
useEffect(() => {
loadProducts(undefined, sortBy)
}, [sortBy])
这是因为我不想每次都进行过滤和排序,即使其中只有一个应该工作,因为我认为当用户只输入数据时,排序也会工作,反之亦然。
这是我的fetchProducts操作:
import { filterProducts, sortProducts } from './../../util/util';
export const fetchProducts = (products, filters, sortBy) => {
if (filters && filters.length) {
products = filterProducts(products, filters);
}
if (sortBy) {
sortProducts(products, sortBy);
}
return {
type: FETCH_PRODUCTS,
payload: products
}
}
在fetchProducts中,您正在更改产品,这不是一个好主意,请尝试products = sortProducts([...products], sortBy);
。
如果state.filters的初始值是[]
,sortBy的初始值为false或工作默认排序,则只需要一个效果。
正如skyboyer评论的那样;如果在用户更改过滤器或排序时进行异步处理,则应避免出现竞争条件。
以下是如何写出效果:
useEffect(() => {
const cancel = {current:false};
//add cancel, only dispatch fetchProducts when it's
// the latest result from user interaction
loadProducts(filters, sortBy, cancel);
return ()=>cancel.current=true;
//added loadProducts as an effect dependency
// the linter should have warned you about it
}, [filters, loadProducts, sortBy])
const mapDispatchToProps = (dispatch) => ({
loadProducts: (filters, sortBy, cancel) => {
fetch('certain API').then(res => res.json()).then(json => {
//only dispatch if this is the latest list of products
// if user changed something during fetching then don't
// set products
cancel.current || dispatch(fetchProducts(json.products, filters, sortBy));
}).catch(err => 'error fetching data');
}
});
如果过滤器最初是[]
,sortBy最初有一个工作值或为false,那么这应该只是工作。
如果要在单个useEffect
调用中处理所有逻辑,可以从useEffect中取出所有道具依赖[filters, sortBy]
。
useEffect(() => {
//This runs all the time a component (re)renders
});
现在,在useEffect
中,您必须有条件地调用fetch操作,这取决于道具的更改。您可以使用useRef
来跟踪道具以前的值。下面是草稿。
function App(props){
const {products = [], filter, sortBy} = props;
const filterRef = useRef();
const sortRef = useRef();
const loadedRef = useRef(false);
// The effect runs all the time
useEffect(() => {
if(!loadedRef.current){
console.log("Dispatch the loadProducts action");
//Update ref
loadedRef.current = true;
}else{
if(sortBy !== sortRef.current){
console.log("Dispatch the filter action");
// Update ref
sortRef.current = sortBy;
// return after this line if you want to avoid next if condition;
}
if(filter !== filterRef.current){
console.log("Dispatch the sort action");
//Update ref
filterRef.current = filter;
}
}
});
return <div>{products.map(product => <h1>{product}</h1>)}</div>
}