使用 Redux Saga 每 X 秒发送一次动作
Dispatch action every X second using Redux Saga
作为 redux-saga 的新手,我正在尝试设置一个对动作 LANGUAGE_START_CYCLE
做出反应并每 3 秒循环一次动作 LANGUAGE_CYCLE
的传奇。
但是传奇 LANGUAGE_CYCLE
从来没有像我将 LANGUAGE_START_CYCLE
发送到 Redux 商店时所期望的那样 运行。
知道我做错了什么吗?我怀疑这是一个简单的错误,因为我的其他 sagas 运行ning 还不错。
// constants/ActionTypes.js
export const LANGUAGE_SET_ACTIVE = "LANGUAGE_SET_ACTIVE";
export const LANGUAGE_START_CYCLE = "LANGUAGE_START_CYCLE";
export const LANGUAGE_STOP_CYCLE = "LANGUAGE_STOP_CYCLE";
export const LANGUAGE_CYCLE = "LANGUAGE_CYCLE";
// actions/language.js
export const cycleLanguage = () => {
return {
type: ActionTypes.LANGUAGE_CYCLE
}
};
// languageSaga.js
import { actionChannel, call, take, put, race } from 'redux-saga/effects'
import * as ActionTypes from '../constants/ActionTypes';
import * as actions from '../actions/language';
const wait = ms => {
new Promise(resolve => {
setTimeout(() => resolve(), ms)
})
};
export default function * languageSaga() {
const channel = yield actionChannel(ActionTypes.LANGUAGE_START_CYCLE);
while (yield take(channel)) {
while (true) {
const { stopped } = yield race({
wait: call(wait, 3000),
stopped: take(ActionTypes.LANGUAGE_STOP_CYCLE)
});
if (!stopped) {
yield put(actions.cycleLanguage());
} else {
break;
}
}
}
}
// sagas.js (root sagas)
export default function * sagas() {
yield [
directorySaga(), // Another saga which works fine
pusherSaga(), // Another saga which works fine
languageSaga()
]
}
我的其他 sagas 之一的例子,它正在运行:
// directorySaga.js
function * fetchDirectory(action) {
try {
const directory = yield call(Api.fetchDirectory, action.id);
yield put(fetchDirectorySucceeded(directory));
} catch (e) {
yield put(fetchDirectoryFailed(e.message));
}
}
export default function * directorySaga() {
yield * takeLatest(ActionTypes.DIRECTORY_REQUESTED, fetchDirectory);
}
我要在这里回答我的问题。
我可以使用上面的代码,但是当我触发操作时,我使用 Redux Dev Tools 将操作发送到商店。
我使用工具手动调度 LANGUAGE_START_CYCLE
,这改变了状态 - 但显然这没有通知 saga 中间件并且我的频道从未更新过:
但是在我的组件之一中使用简单按钮时:
<button onClick={() => dispatch(actions.startCycle())}>
Start
</button>
<button onClick={() => dispatch(actions.stopCycle())}>
Stop
</button>
saga 中间件已收到通知。
更新
我的商店配置是:
import { createStore, applyMiddleware, compose } from 'redux'
import createSagaMiddleware from 'redux-saga';
import rootReducer from '../reducers/index';
import sagas from '../sagas/index';
export default function configureStore(initialState) {
const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, initialState, compose(
applyMiddleware(sagaMiddleware),
window.devToolsExtension ? window.devToolsExtension() : f => f
));
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
const nextReducer = require('../reducers');
store.replaceReducer(nextReducer);
});
}
sagaMiddleware.run(sagas);
return store;
}
我认为等待函数的类型不对。
你必须这样修复。
const wait = ms => {
return new Promise(resolve => {
setTimeout(() => resolve(), ms)
})
}
作为 redux-saga 的新手,我正在尝试设置一个对动作 LANGUAGE_START_CYCLE
做出反应并每 3 秒循环一次动作 LANGUAGE_CYCLE
的传奇。
但是传奇 LANGUAGE_CYCLE
从来没有像我将 LANGUAGE_START_CYCLE
发送到 Redux 商店时所期望的那样 运行。
知道我做错了什么吗?我怀疑这是一个简单的错误,因为我的其他 sagas 运行ning 还不错。
// constants/ActionTypes.js
export const LANGUAGE_SET_ACTIVE = "LANGUAGE_SET_ACTIVE";
export const LANGUAGE_START_CYCLE = "LANGUAGE_START_CYCLE";
export const LANGUAGE_STOP_CYCLE = "LANGUAGE_STOP_CYCLE";
export const LANGUAGE_CYCLE = "LANGUAGE_CYCLE";
// actions/language.js
export const cycleLanguage = () => {
return {
type: ActionTypes.LANGUAGE_CYCLE
}
};
// languageSaga.js
import { actionChannel, call, take, put, race } from 'redux-saga/effects'
import * as ActionTypes from '../constants/ActionTypes';
import * as actions from '../actions/language';
const wait = ms => {
new Promise(resolve => {
setTimeout(() => resolve(), ms)
})
};
export default function * languageSaga() {
const channel = yield actionChannel(ActionTypes.LANGUAGE_START_CYCLE);
while (yield take(channel)) {
while (true) {
const { stopped } = yield race({
wait: call(wait, 3000),
stopped: take(ActionTypes.LANGUAGE_STOP_CYCLE)
});
if (!stopped) {
yield put(actions.cycleLanguage());
} else {
break;
}
}
}
}
// sagas.js (root sagas)
export default function * sagas() {
yield [
directorySaga(), // Another saga which works fine
pusherSaga(), // Another saga which works fine
languageSaga()
]
}
我的其他 sagas 之一的例子,它正在运行:
// directorySaga.js
function * fetchDirectory(action) {
try {
const directory = yield call(Api.fetchDirectory, action.id);
yield put(fetchDirectorySucceeded(directory));
} catch (e) {
yield put(fetchDirectoryFailed(e.message));
}
}
export default function * directorySaga() {
yield * takeLatest(ActionTypes.DIRECTORY_REQUESTED, fetchDirectory);
}
我要在这里回答我的问题。
我可以使用上面的代码,但是当我触发操作时,我使用 Redux Dev Tools 将操作发送到商店。
我使用工具手动调度 LANGUAGE_START_CYCLE
,这改变了状态 - 但显然这没有通知 saga 中间件并且我的频道从未更新过:
但是在我的组件之一中使用简单按钮时:
<button onClick={() => dispatch(actions.startCycle())}>
Start
</button>
<button onClick={() => dispatch(actions.stopCycle())}>
Stop
</button>
saga 中间件已收到通知。
更新
我的商店配置是:
import { createStore, applyMiddleware, compose } from 'redux'
import createSagaMiddleware from 'redux-saga';
import rootReducer from '../reducers/index';
import sagas from '../sagas/index';
export default function configureStore(initialState) {
const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, initialState, compose(
applyMiddleware(sagaMiddleware),
window.devToolsExtension ? window.devToolsExtension() : f => f
));
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
const nextReducer = require('../reducers');
store.replaceReducer(nextReducer);
});
}
sagaMiddleware.run(sagas);
return store;
}
我认为等待函数的类型不对。 你必须这样修复。
const wait = ms => {
return new Promise(resolve => {
setTimeout(() => resolve(), ms)
})
}