Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/409.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在我的情况下只使用一次react hook Useffect?_Javascript_Reactjs_Redux_React Redux_React Hooks - Fatal编程技术网

Javascript 如何在我的情况下只使用一次react hook Useffect?

Javascript 如何在我的情况下只使用一次react hook Useffect?,javascript,reactjs,redux,react-redux,react-hooks,Javascript,Reactjs,Redux,React Redux,React Hooks,我认为我的问题有一段时间似乎是重复的,但我猜不是,我检查了许多标题相同但案例不同的问题 问题是,我被迫在代码中使用了两次react钩子,我甚至想将它们改为三次,但我觉得这是一种不好的做法,我相信有解决方法 我有我想最初获取的数据,我实现了通过第一次useEffect调用,以后可以对数据进行筛选或排序,我有筛选复选框和选择排序查询,选中复选框将筛选数据,选择选项将对其排序,我正在使用redux和react reduxconnect方法创建状态树,其中包括过滤器和排序 //the first c

我认为我的问题有一段时间似乎是重复的,但我猜不是,我检查了许多标题相同但案例不同的问题

问题是,我被迫在代码中使用了两次react钩子,我甚至想将它们改为三次,但我觉得这是一种不好的做法,我相信有解决方法

我有我想最初获取的数据,我实现了通过第一次useEffect调用,以后可以对数据进行筛选或排序,我有筛选复选框和选择排序查询,选中复选框将筛选数据,选择选项将对其排序,我正在使用redux和react reduxconnect方法创建状态树,其中包括过滤器和排序

  //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函数不需要任何参数,第二个调用是在执行筛选或排序时,在本例中,函数需要参数,并且在任何筛选器或排序被更改时都能工作

我甚至想把第二个电话分成两个电话,这样给他们打三个电话:

 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
    }
}


如果要在单个
useffect
调用中处理所有逻辑,可以从useffect中取出所有的道具依赖项
[filters,sortBy]

useEffect(() => {
  //This runs all the time a component (re)renders
});
现在在
useffect
中,您必须根据道具的变化有条件地调用获取操作。您可以使用
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>
}
功能应用程序(道具){
const{products=[],filter,sortBy}=props;
常量filterf=useRef();
const sortRef=useRef();
const loadedRef=useRef(false);
//效果一直在运行
useffect(()=>{
如果(!loadedRef.current){
console.log(“发送loadProducts操作”);
//更新参考
loadedRef.current=真;
}否则{
if(排序比!==sortRef.current){
日志(“分派过滤器操作”);
//更新参考
sortRef.current=sortBy;
//如果要避免下一个if条件,请在此行后返回;
}
如果(过滤器!==filterRef.current){
log(“分派排序操作”);
//更新参考
filterRef.current=过滤器;
}
}
});
返回{products.map(product=>{product})}
}

在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,那么这应该可以正常工作。

看起来过滤/排序是在UI端进行的。那么,如果让它成为
mapStateToProps
的一部分而不是action creator,该怎么办呢?顺便说一句,如果你现在没有清理,你的
useEffect
可能会陷入竞争状态,如果你能够一个接一个地发送多个请求,也可能会导致UI闪烁。@skyboyer,你能解释一下我如何改进我的代码吗!!fetchProducts是我的操作创建者,但我在loadProducts函数中完成了所有异步工作,请检查我问题中的最后一段代码@Saherlegendy用代码更新了我的答案,以避免“谢谢”,它工作得很好,顺便说一句,您忘了在useEffect中将cacel作为loadProducts函数调用的参数传递!抱歉,您的最后一句话仍然有效吗,因为我认为loadProducts是异步的,因为它使用ajax函数调用'fetch'@saheregendy,我忘记删除最后一句话了,它确实变得有点复杂,因为您现在必须传递一个cancel,以确保您不只是在响应传入时渲染响应,而是仅在响应是针对最后一个用户输入时渲染响应。我会更新答案。