如何在 Flatlist 上使用无限滚动的 redux saga?
How to use redux saga with infinite scroll on Flatlist?
我正在开发我的第一个 React Native 应用程序,这是我第一次使用 redux 和 redux saga。所以我建立了一个 Flatlist 来无限滚动,API 端点是 return 的帖子(每页 10 个)。但我不知道如何使用 reducer 来 return 帖子,控制加载指示器并跟踪商店中的页码,使用 redux saga。
我的代码如下:
Home.js
this.state = {
page: 1,
totalPages: 10,
loading: false,
}
componentDidMount() {
this.loadMorePosts();
}
loadMorePosts = () => {
this.setState(() => { loading: true });
this.setState(() => { page: this.state.page++ });
this.props.loadPosts(this.state.page);
}
<AnimatedFlatList
...
onEndReached={this.loadMorePosts}
onEndReachedThreshold={0.2}
/>
const mapStateToProps = state => ({
posts: state.posts,
});
帖子操作
export function loadPosts(page){
return {
type: Types.FETCH_POSTS,
payload: { page }
};
}
帖子传奇
export function* fetchPosts(action) {
const response = yield call(api.get, `/posts/${action.payload.page}`);
yield put({ type: Types.LOAD_POSTS, payload: { posts: response.data } });
}
帖子减速器
export default function posts(state = initialState, action) {
switch(action.type) {
case Types.LOAD_POSTS:
return [ ...state, ...action.payload.posts ];
default:
return state;
}
}
有了这个我可以获取帖子并加载到 Flatlist 中,但是如果我更改屏幕我会忘记实际页码,它将在 Home.js 构造函数中再次设置为 0。并且没有视觉反馈,因为加载状态没有用 mapStateToProps 函数定义...
谁能帮我解决这个问题?
扩展评论:(未经测试的代码但原则在那里)。
传奇
export function* fetchPosts(action) {
try {
yield put({ type: Types.LOAD_POSTS_START, payload: { page: action.payload.page } });
const response = yield call(api.get, `/posts/${action.payload.page}`);
yield put({ type: Types.LOAD_POSTS, payload: { posts: response.data } });
}
catch {
//perhaps roll back page count?
yield put({ type: Types.LOAD_POSTS_END, payload: { } });
}
}
减速器
const initialState = {
isLoading: false,
currentPage: 0,
posts: []
}
export default function posts(state = initialState, action) {
switch(action.type) {
case Types.LOAD_POSTS_START:
return {
...state,
currentPage: action.payload.page,
isLoading: true
};
case Types.LOAD_POSTS_END:
return {
...state,
isLoading: false
};
case Types.LOAD_POSTS:
return {
...state,
isLoading: false,
posts: [ ...state.posts, ...action.payload.posts ]
};
default:
return state;
}
}
然后在您的组件中连接到此状态,而不是将其存储在组件状态对象中
做一个 saga/task 只做一个 fetch
和 returns 这样的承诺:
const fetchAction = (input, init) => {
let resolve;
const promise = new Promise(resolveArg => resolve = resolveArg)
return { type:'FETCH_ACTION', input, init, promise, resolve }
}
function fetchActionWorker({ input, init, resolve}) {
const res = yield call(fetch, input, init);
resolve(res);
}
function* fetchActionWatcher() {
yield takeEvery('FETCH_ACTION', fetchWorker);
}
然后像这样使用它:
class List extends Component {
render() {
return <Button title="fetch" onPress={this.doFetch} />
}
doFetch = async () => {
const res = await dispatch(fetchAction('url', { method:'GET' })).promise;
}
}
立即调用 fetch
操作即可获得承诺。
我正在开发我的第一个 React Native 应用程序,这是我第一次使用 redux 和 redux saga。所以我建立了一个 Flatlist 来无限滚动,API 端点是 return 的帖子(每页 10 个)。但我不知道如何使用 reducer 来 return 帖子,控制加载指示器并跟踪商店中的页码,使用 redux saga。
我的代码如下:
Home.js
this.state = {
page: 1,
totalPages: 10,
loading: false,
}
componentDidMount() {
this.loadMorePosts();
}
loadMorePosts = () => {
this.setState(() => { loading: true });
this.setState(() => { page: this.state.page++ });
this.props.loadPosts(this.state.page);
}
<AnimatedFlatList
...
onEndReached={this.loadMorePosts}
onEndReachedThreshold={0.2}
/>
const mapStateToProps = state => ({
posts: state.posts,
});
帖子操作
export function loadPosts(page){
return {
type: Types.FETCH_POSTS,
payload: { page }
};
}
帖子传奇
export function* fetchPosts(action) {
const response = yield call(api.get, `/posts/${action.payload.page}`);
yield put({ type: Types.LOAD_POSTS, payload: { posts: response.data } });
}
帖子减速器
export default function posts(state = initialState, action) {
switch(action.type) {
case Types.LOAD_POSTS:
return [ ...state, ...action.payload.posts ];
default:
return state;
}
}
有了这个我可以获取帖子并加载到 Flatlist 中,但是如果我更改屏幕我会忘记实际页码,它将在 Home.js 构造函数中再次设置为 0。并且没有视觉反馈,因为加载状态没有用 mapStateToProps 函数定义...
谁能帮我解决这个问题?
扩展评论:(未经测试的代码但原则在那里)。
传奇
export function* fetchPosts(action) {
try {
yield put({ type: Types.LOAD_POSTS_START, payload: { page: action.payload.page } });
const response = yield call(api.get, `/posts/${action.payload.page}`);
yield put({ type: Types.LOAD_POSTS, payload: { posts: response.data } });
}
catch {
//perhaps roll back page count?
yield put({ type: Types.LOAD_POSTS_END, payload: { } });
}
}
减速器
const initialState = {
isLoading: false,
currentPage: 0,
posts: []
}
export default function posts(state = initialState, action) {
switch(action.type) {
case Types.LOAD_POSTS_START:
return {
...state,
currentPage: action.payload.page,
isLoading: true
};
case Types.LOAD_POSTS_END:
return {
...state,
isLoading: false
};
case Types.LOAD_POSTS:
return {
...state,
isLoading: false,
posts: [ ...state.posts, ...action.payload.posts ]
};
default:
return state;
}
}
然后在您的组件中连接到此状态,而不是将其存储在组件状态对象中
做一个 saga/task 只做一个 fetch
和 returns 这样的承诺:
const fetchAction = (input, init) => {
let resolve;
const promise = new Promise(resolveArg => resolve = resolveArg)
return { type:'FETCH_ACTION', input, init, promise, resolve }
}
function fetchActionWorker({ input, init, resolve}) {
const res = yield call(fetch, input, init);
resolve(res);
}
function* fetchActionWatcher() {
yield takeEvery('FETCH_ACTION', fetchWorker);
}
然后像这样使用它:
class List extends Component {
render() {
return <Button title="fetch" onPress={this.doFetch} />
}
doFetch = async () => {
const res = await dispatch(fetchAction('url', { method:'GET' })).promise;
}
}
立即调用 fetch
操作即可获得承诺。