直到现在,我一直在使用redux-thunk进行异步操作。在应用程序启动时,我不得不从某些服务器加载一些数据。因此,我要做的是创建异步操作,然后使用异步/等待以了解它们何时完成。在获取异步操作时,我呈现了一个启动画面。他们完成后,我将启动应用程序。
现在,我正在切换到redux sagas,但我不知道如何与他们合作。我不能使用异步/等待。我认为在商店的每个需要获取数据的对象中都有一个布尔变量。但是我想知道是否有任何模式可以以干净的方式对其进行管理。有人知道为此目的有任何模式吗?
// example with thunks
import { someAsyncAction, someAsyncAction2 } from './actions';
const initialDispatches = async (store) => {
await store.dispatch(someAsyncAction());
await store.dispatch(someAsyncAction2());
};
export default initialDispatches;
答案 0 :(得分:0)
我认为在这种情况下没有正确/错误的模式。
我为您提供了一个使用传奇如何实现目标的示例。
基本思想:每个资源都有一个单独的传奇(例如,我以前将其分解为特征sagas),而初始化则有一个传奇。 然后,主根传奇将并行运行它们,您将能够在应用程序中的某个地方触发初始化传奇,并使其全部发生:
注意:该示例非常幼稚且简单,您应该找到一种更好的方式来组织所有内容,我只是想使其保持简单。
const {Provider, connect} = ReactRedux;
const {createStore, applyMiddleware} = Redux;
const createSagaMiddleware = ReduxSaga.default;
const {takeEvery, takeLatest} = ReduxSaga;
const {put, call, all, fork} = ReduxSaga.effects;
const initialState = {
fruits: [],
vegtables: []
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'SET_FRUITS':
return {
...state,
fruits: [
...action.payload.fruits
]
}
case 'SET_VEGTABLES':
return {
...state,
vegtables: [
...action.payload.vegtables
]
}
}
return state;
};
//====== VEGTABLES ====== //
async function fetchVegtables() {
return await new Promise((res) => {
setTimeout(() => res([
'Cuecumber',
'Carrot',
'LEttuce'
]), 3000)
});
}
function* getVegtables() {
const vegtables = yield call(fetchVegtables);
yield put({ type: 'SET_VEGTABLES', payload: { vegtables } })
}
function* vegtablesSaga() {
yield takeEvery('GET_VEGTABLES', getVegtables);
}
//====== VEGTABLES ====== //
//====== FRUITS ====== //
async function fetchFruits() {
return await new Promise((res) => {
setTimeout(() => res([
'Banana',
'Apple',
'Peach'
]), 2000)
});
}
function* getFruits() {
const fruits = yield call(fetchFruits);
console.log(fruits)
yield put({ type: 'SET_FRUITS', payload: { fruits } })
}
function* fruitsSaga() {
yield takeEvery('GET_FRUITS', getFruits);
}
//====== FRUITS ====== //
//====== INIT ====== //
function* initData() {
yield all([
put({ type: 'GET_FRUITS' }),
put({ type: 'GET_VEGTABLES' })
]);
}
function* initSaga() {
yield takeLatest('INIT', initData);
}
//====== INIT ====== //
// Sagas
function* rootSaga() {
yield all([
yield fork(initSaga),
yield fork(fruitsSaga),
yield fork(vegtablesSaga),
]);
}
// Component
class App extends React.Component {
componentDidMount() {
this.props.dispatch({ type: 'INIT' });
}
render () {
return (
<div>
<div>fruits: {this.props.fruits.join()}</div>
<div>vegtables: {this.props.vegtables.join()}</div>
</div>
);
}
}
// Store
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
);
sagaMiddleware.run(rootSaga);
const ConnectedApp = connect((state) => ({
fruits: state.fruits,
vegtables: state.vegtables
}))(App);
// Container component
ReactDOM.render(
<Provider store={store}>
<ConnectedApp />
</Provider>,
document.getElementById('root')
);
如您所见,我有两种资源:水果和蔬菜。 每个资源都有其自己的传奇,负责监视在某处分发的 GET 操作。 它们中的每个都使用诸如调用,放置等基本的传奇效果来异步获取资源,然后将其分派到商店(然后由reducer处理)。
此外,我还设置了 initSaga ,该 initSaga 使用 all 效果来触发所有资源以并行方式获取Sagas。
您可以看到整个示例在此处运行:
答案 1 :(得分:0)
我写过关于在redux-saga之上创建一个结构,以通过提供初始操作然后基于操作结果加载/成功/错误状态来促进异步操作的信息。它分为两部分,首先是同步,然后是异步。
基本上,它使您可以像对象一样声明式地编写缩减器。您只需要调用初始操作,传奇便会处理其余的操作,并且在触发加载/成功/错误操作时,UI可以响应结果。减速器的外观如下。
const counterAsync = {
initialState: {
incrementAsync_result: null,
incrementAsync_loading: false,
incrementAsync_success: false,
incrementAsync_error: false,
},
incrementAsync: {
asyncOperation: incrementAPI,
action: ({number}) => {
type: ACTION_INCREMENT_ASYNC,
payload: {
number: number
}
}
loading: {
action: (payload) => {
return {
type: ACTION_INCREMENT_ASYNC,
payload: { ...payload }
}
},
reducer: (state, action) => {
state.incrementAsync_loading = true
state.incrementAsync_success = false
state.incrementAsync_error = false
}
},
success: {
action: (payload) => {
return {
type: ACTION_INCREMENT_ASYNC,
payload: { ...payload }
}
},
reducer: (state, action) => {
state.incrementAsync_result = action.payload
state.incrementAsync_loading = false
state.incrementAsync_success = true
state.incrementAsync_error = false
}
},
fail: {
action: (payload) => {
return {
type: ACTION_INCREMENT_ASYNC,
payload: { ...payload }
}
},
reducer: (state, action) => {
state.incrementAsync_result = action.payload
state.incrementAsync_loading = false
state.incrementAsync_success = false
state.incrementAsync_error = true
}
}
},
}
我们在工作中使用了这种模式的重量稍重的版本,它比香草redux / saga好得多。
让我知道您是否有任何疑问!
https://medium.com/@m.razajamil/declarative-redux-part-1-49a9c1b43805 https://medium.com/@m.razajamil/declarative-redux-part-2-a0ed084e4e31