Redux Saga 阻塞
Redux Saga Blocking
我是 Redux Saga 和一般生成器的新手,所以我正在努力思考如何在分派后执行其余代码之前 "await" 分派的动作。
例如:
// Sideeffect to load messages on mount
useEffect(() => {
let mounted = true;
if(mounted) {
dispatch({ type: 'GET_THREAD_MESSAGES', threadId: _id })
setIsLoading(false);
}
return () => {
dispatch({ type: 'CLEAR_FOCUSSED_MESSAGES' })
}
}, [])
当组件首次挂载时,它将调度 GET_THREAD_MESSAGES
。我在我的 rootSaga
中观察了以下操作:
export default function* rootSaga() {
yield all([
...
watchGetThreadMessages(),
watchClearFocussedMessages()
])
}
我适用的故事:
export function* watchGetThreadMessages() {
yield takeEvery('GET_THREAD_MESSAGES', getThreadMessages)
}
export function* getThreadMessages({ threadId, lastDate }) {
const { token } = yield select(state => state.auth);
try {
const { data } = yield call(getMessages, token, threadId)
yield put({
type: 'GET_THREAD_MESSAGES_SUCCESS',
allMessages: data.messages,
totalMessages: data.count
})
console.log('retrieved messages')
} catch(err) {
console.log(err)
}
}
getMessages
是对我的端点从服务器获取数据的 axios 调用。问题是我的 setIsLoading
在组件安装 dispatch
之后会在我完成从 axios 调用中获取消息之前触发,因为它是异步的。通常,如果我正在获取组件内的数据,我只会等待此响应,但不确定如何等待 dispatch
操作。我通过将 setIsLoading 传递给调度并在 saga 中触发 setIsLoading 来绕过它,但这不是最优雅的解决方案,如果有的话,我想知道更好的过程。
有什么想法或建议吗?非常感谢。
由于您的操作只是简单的同步函数,因此无法跟踪组件内的 isLoading
状态。您必须将 isLoading
保留在 redux 存储中,并连接到您的组件。每当调度 GET_THREAD_MESSAGES_SUCCESS
操作时,reducer 会将 isLoading
值更改为 false
。例如:
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
// isLoading prop is mapped to state.messages.isLoading
function YourComponent({ isLoading, dispatch }) {
useEffect(() => {
dispatch({ type: 'GET_THREAD_MESSAGES', threadId: 'someId' });
}, []);
if(isLoading) {
return <div>Some loader</div>;
}
return <div>Your component</div>;
}
function mapStateToProps(state) {
return {
isLoading: state.messages.isLoading,
};
}
export default connect(mapStateToProps)(YourComponent);
您的消息缩减程序可能如下所示:
export default function messagesReducer(state, action) {
switch (action.type) {
case 'GET_THREAD_MESSAGES':
return {
...state,
isLoading: true,
};
case 'GET_THREAD_MESSAGES_SUCCESS':
return {
...state,
isLoading: false,
allMessages: action.allMessages,
totalMessages: action.totalMessages,
};
default:
return state;
}
}
我是 Redux Saga 和一般生成器的新手,所以我正在努力思考如何在分派后执行其余代码之前 "await" 分派的动作。
例如:
// Sideeffect to load messages on mount
useEffect(() => {
let mounted = true;
if(mounted) {
dispatch({ type: 'GET_THREAD_MESSAGES', threadId: _id })
setIsLoading(false);
}
return () => {
dispatch({ type: 'CLEAR_FOCUSSED_MESSAGES' })
}
}, [])
当组件首次挂载时,它将调度 GET_THREAD_MESSAGES
。我在我的 rootSaga
中观察了以下操作:
export default function* rootSaga() {
yield all([
...
watchGetThreadMessages(),
watchClearFocussedMessages()
])
}
我适用的故事:
export function* watchGetThreadMessages() {
yield takeEvery('GET_THREAD_MESSAGES', getThreadMessages)
}
export function* getThreadMessages({ threadId, lastDate }) {
const { token } = yield select(state => state.auth);
try {
const { data } = yield call(getMessages, token, threadId)
yield put({
type: 'GET_THREAD_MESSAGES_SUCCESS',
allMessages: data.messages,
totalMessages: data.count
})
console.log('retrieved messages')
} catch(err) {
console.log(err)
}
}
getMessages
是对我的端点从服务器获取数据的 axios 调用。问题是我的 setIsLoading
在组件安装 dispatch
之后会在我完成从 axios 调用中获取消息之前触发,因为它是异步的。通常,如果我正在获取组件内的数据,我只会等待此响应,但不确定如何等待 dispatch
操作。我通过将 setIsLoading 传递给调度并在 saga 中触发 setIsLoading 来绕过它,但这不是最优雅的解决方案,如果有的话,我想知道更好的过程。
有什么想法或建议吗?非常感谢。
由于您的操作只是简单的同步函数,因此无法跟踪组件内的 isLoading
状态。您必须将 isLoading
保留在 redux 存储中,并连接到您的组件。每当调度 GET_THREAD_MESSAGES_SUCCESS
操作时,reducer 会将 isLoading
值更改为 false
。例如:
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
// isLoading prop is mapped to state.messages.isLoading
function YourComponent({ isLoading, dispatch }) {
useEffect(() => {
dispatch({ type: 'GET_THREAD_MESSAGES', threadId: 'someId' });
}, []);
if(isLoading) {
return <div>Some loader</div>;
}
return <div>Your component</div>;
}
function mapStateToProps(state) {
return {
isLoading: state.messages.isLoading,
};
}
export default connect(mapStateToProps)(YourComponent);
您的消息缩减程序可能如下所示:
export default function messagesReducer(state, action) {
switch (action.type) {
case 'GET_THREAD_MESSAGES':
return {
...state,
isLoading: true,
};
case 'GET_THREAD_MESSAGES_SUCCESS':
return {
...state,
isLoading: false,
allMessages: action.allMessages,
totalMessages: action.totalMessages,
};
default:
return state;
}
}