Reactjs 使用useEffect进行分页-如果请求失败,如何还原页码?
我正在测试带有react钩子的简单分页,并想知道如何处理失败以使其保持在有效状态 伪代码: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();
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页
我考虑的另一个选项是,我可能只在获得页面的数据后才增加页面,但随后我会在使用中创建无限循环,因为页面在获取数据后会发生更改?您可以添加另一个表示我们希望看到的页面的状态,假设它已加载
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吗?