Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.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
Reactjs 使用useEffect进行分页-如果请求失败,如何还原页码?_Reactjs_React Hooks - Fatal编程技术网

Reactjs 使用useEffect进行分页-如果请求失败,如何还原页码?

Reactjs 使用useEffect进行分页-如果请求失败,如何还原页码?,reactjs,react-hooks,Reactjs,React Hooks,我正在测试带有react钩子的简单分页,并想知道如何处理失败以使其保持在有效状态 伪代码: function reducer(state, action) { switch (action.type) { case 'next': return {page: state.page + 1}; case 'prev': return {page: state.page - 1}; default: throw new Error();

我正在测试带有react钩子的简单分页,并想知道如何处理失败以使其保持在有效状态

伪代码:

function reducer(state, action) {
  switch (action.type) {
    case 'next':
      return {page: state.page + 1};
    case 'prev':
      return {page: state.page - 1};
    default:
      throw new Error();
  }
}

function Page() {
  const [state, dispatch] = useReducer(reducer, { page: 1});

  useEffect(() => {
    loadMore(state.page)
    .then(r => console.log(r))
    .catch(e => {
      // how to revert page without triggering this effect?
      // cause if I do dispatch({type: 'prev'}) page will change, and this will re-run
      console.log(e)
    })
  }, state.page)

  return (
    <>
      Page: {state.page}
      <button onClick={() => dispatch({type: 'prev'})}>-</button>
      <button onClick={() => dispatch({type: 'next'})}>+</button>
    </>
  );
}
功能减速机(状态、动作){
开关(动作类型){
“下一个”案例:
返回{page:state.page+1};
案例“prev”:
返回{page:state.page-1};
违约:
抛出新错误();
}
}
功能页(){
const[state,dispatch]=useReducer(reducer,{page:1});
useffect(()=>{
loadMore(state.page)
.then(r=>console.log(r))
.catch(e=>{
//如何在不触发此效果的情况下还原页面?
//因为如果我执行分派({type:'prev'}),页面将更改,这将重新运行
控制台日志(e)
})
},state.page)
返回(
页面:{state.Page}
分派({type:'prev'})}>-
分派({type:'next'})}>+
);
}
让我们以这个场景为例:

  • 我们从第一页开始
  • 用户单击下一步
  • 页面在状态中增加
  • useEffect激发,网络请求失败
  • 处于状态的页面为2,但实际数据为第1页
我不能在catch上调度页面更改事件,因为它会触发refetch,我不想这样做


我考虑的另一个选项是,我可能只在获得页面的数据后才增加页面,但随后我会在使用中创建无限循环,因为页面在获取数据后会发生更改?

您可以添加另一个表示我们希望看到的页面的状态,假设它已加载

function reducer(state, action) {
  switch (action.type) {
    case 'failed':
      return { ...state, requestedPage: null };
    case 'loaded':
      return { page: action.page, requestedPage: null };
    case 'next':
      return { ...state, requestedPage: state.page + 1 };
    case 'prev':
      return { ...state, requestedPage: state.page - 1 };
    default:
      throw new Error();
  }
}

const Page = () => {
  const [{ page, requestedPage }, dispatch] = useReducer(reducer, {
    page: 1,
    requestedPage: null,
  });

  useEffect(() => {
    loadMore(requestedPage)
      .then((r) => {
        dispatch({ type: 'loaded', page: requestedPage });
        console.log(r);
      })
      .catch((e) => {
        dispatch({ type: 'failed' });
        console.error(e);
      });
    // Make sure the dependencies are an array
  }, [requestedPage]);

  // Optimistically render the requestedPage (with a spinner?) if present,
  // otherwise current page.
  return (
    <>
      Page: {requestedPage || page}
      <button onClick={() => dispatch({ type: 'prev' })}>-</button>
      <button onClick={() => dispatch({ type: 'next' })}>+</button>
    </>
  );
};
功能减速机(状态、动作){
开关(动作类型){
案例“失败”:
返回{…状态,requestedPage:null};
“已加载”案例:
返回{page:action.page,requestedPage:null};
“下一个”案例:
返回{…状态,requestedPage:state.page+1};
案例“prev”:
返回{…state,requestedPage:state.page-1};
违约:
抛出新错误();
}
}
常量页=()=>{
const[{page,requestedPage},dispatch]=useReducer(reducer{
页码:1,
requestedPage:null,
});
useffect(()=>{
加载更多(请求页面)
。然后((r)=>{
分派({type:'loaded',page:requestedPage});
控制台日志(r);
})
.catch((e)=>{
分派({type:'failed'});
控制台错误(e);
});
//确保依赖项是一个数组
},[requestedPage]);
//乐观地呈现请求的页面(使用微调器?),如果存在,
//否则为当前页面。
返回(
页面:{requestedPage | | Page}
分派({type:'prev'})}>-
分派({type:'next'})}>+
);
};

您也可以简单地删除
useffect
并使用该功能:

let fetch = (page, isNext)=>{

 loadMore(page)
    .then(r => {
      // ..
      isNext ? dispatch({type: 'next'}):dispatch({type: 'prev'});
    })
    .catch(e => {
      // Don't dispatch anything, you will remain on same page
    })

}
现在,当用户单击next时,只需调用
fetch(state.page+1,true)
。如果她单击prev btn,请使用
fetch(state.page-1,false)

我会使用
useRef()
来保留关于成功的上一页。如果当前调用失败,请通过设置返回上一页。输入
useffect()
时,检查当前页面和ref中存储的页面是否相同,如果相同,则不执行任何操作

function reducer(state, { type, page }) {
  switch (type) {
    case 'set':
      return { page };
    case 'next':
      return { page: state.page + 1 };
    case 'prev':
      return { page: state.page - 1 };
    default:
      throw new Error();
  }
}

function Page() {
  const [state, dispatch] = useReducer(reducer, { page: 1 });

  const currentPage = useRef();

  useEffect(() => {
    if (currentPage.current === state.page) return;

    loadMore(state.page)
    .then(r => {
      currentPage.current = state.page;
    })
    .catch(e => {
      dispatch({ type: 'set', page: currentPage.current || 1 }); // if currentPage.current doesn't exist use page 1 as default

      console.log(e)
    })
  }, state.page)

  return (
    <>
      Page: {state.page}
      <button onClick={() => dispatch({type: 'prev'})}>-</button>
      <button onClick={() => dispatch({type: 'next'})}>+</button>
    </>
  );
}
函数缩减器(状态,{type,page}){
开关(类型){
案例“集合”:
返回{page};
“下一个”案例:
返回{page:state.page+1};
案例“prev”:
返回{page:state.page-1};
违约:
抛出新错误();
}
}
功能页(){
const[state,dispatch]=useReducer(reducer,{page:1});
const currentPage=useRef();
useffect(()=>{
if(currentPage.current==state.page)返回;
loadMore(state.page)
.然后(r=>{
currentPage.current=state.page;
})
.catch(e=>{
分派({type:'set',page:currentPage.current | | 1});//如果currentPage.current不存在,则使用第1页作为默认值
控制台日志(e)
})
},state.page)
返回(
页面:{state.Page}
分派({type:'prev'})}>-
分派({type:'next'})}>+
);
}

上一页/下一页的简单解决方案。但如果我需要从另一个useEffect(例如infite scroll)调用fetch,那么会出现同样的问题吗remain@gerasalus你不能在无限滚动场景中也省略useEffect吗?