_.throttle 执行 API 不止一次

_.throttle executing API more than once

我有一个 TimeLine 组件,一次呈现 5 个帖子

当用户滚动到页面末尾时,会调用节流函数。

我正在尝试将请求限制为每秒最多一次,但是 API 被调用了多次

我尝试了几种解决方案,例如:

TimeLine.js

export default function TimeLine() {
    const dispatch = useDispatch();
    const posts = useSelector(state => state.postReducer.posts);
    const loaded = useSelector(state => state.postReducer.loaded);
    const TIMEOUT = 1000;
    
  // Loaded keeps track of loaded posts
    if(loaded === 0){
        API.Post.getAllPosts(loaded)(dispatch);
    }

    if(loaded > 5){
        if(loaded % 5 === 0) window.scrollTo(0, document.body.scrollHeight * 0.6)
        
    }

    window.addEventListener('scroll', () => throttledReq(loaded, TIMEOUT, dispatch));
    
    const classes = useStyle();
    return (
        <div>
            <NewPost  />

            {(posts && posts.length > 0)?posts.map((post, index) => (
                <div key={post._id} className={classes.post}>
                    <Post
                        currentIndex={index}
                        {...post.user}
                        dispatch={dispatch}
                        postID={post._id}
                        postContent={post.text}
                    />
                </div>
            )): false}
        </div>
    );
};


节流功能

const throttledReq = (loaded, TIMEOUT, dispatch) => _.throttle(e => {
    const bottomLimit = document.documentElement.offsetHeight - window.innerHeight;
    if(document.documentElement.scrollTop === bottomLimit){
            API.Post.getAllPosts(loaded)(dispatch);
    }
}, TIMEOUT)();

我的要求

每次滚动时,都会触发 dispatch,这又会重新 运行 组件,添加另一个事件侦听器。这将无限继续下去。

您只希望在第一次呈现组件时添加事件侦听器。您可以使用 useEffect 钩子来做到这一点。

useEffect(() => {
  window.addEventListener('scroll', () => throttledReq(loaded, TIMEOUT, dispatch));
}, []);

末尾的空数组表示它没有任何依赖关系,因此每当组件渲染时它只会 运行 一次。每次重新渲染都不会调用回调。

您的 loaded 值也应使用 useEffect,但在本例中使用 loaded 变量作为依赖项。每次 loaded 更改(以及在第一次渲染时),都会触发回调并评估逻辑。

useEffect(() => {
  if (loaded === 0) {
    API.Post.getAllPosts(loaded)(dispatch);
  }

  if (loaded % 5 === 0) {
    window.scrollTo(0, document.body.scrollHeight * 0.6)
  }
), [loaded]);

由于您试图在到达滚动位置或看到某个元素时调用特定逻辑,因此我建议您看一下 Intersection Observer API,它消除了节流 onscroll函数。