admin管理员组文章数量:1430924
I have been trying to introduce redux-sagas and redux-toolkit to my project. It seems that I am having some wiring problems. Not sure how to fix it. Let me know if you have any ideas. Here is the error I am getting. Here is the link to github
file - configureAppStore.js
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import reducer from './reducer';
import createSagaMiddleware from 'redux-saga';
import tweetSagas from '../saga/tweet.js';
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware];
const middleware = [...getDefaultMiddleware({ thunk: false }), ...middlewares];
const configureAppStore = () => {
// reduxjs/toolkit configureStore enables to dispatch async actions
return configureStore({
reducer: reducer,
middleware: middleware,
});
};
sagaMiddleware.run(tweetSagas);
export default configureAppStore;
file - saga/tweet.js
import { takeEvery, call, put, fork } from 'redux-saga/effects';
import axios from 'axios';
import * as actions from '../store/action/saga.js';
const port = process.env.REACT_APP_PORT;
const hostname = process.env.REACT_APP_LOCALHOST;
const baseURL = `http://${hostname}:${port}`;
function api({ dispatch }) {
return function (next) {
return function* (action) {
if (action.type !== actions.sagaApiCallBegan.type) return next(action);
next(action); // 'sagaApiCallBegan' to show in redux dev tools
const { url, method, onSuccess, onError } = action.payload;
try {
const response = yield call(
async () =>
await axios.request({
baseURL: baseURL,
url,
method,
})
);
if (onSuccess)
yield put(dispatch({ type: onSuccess, payload: response.data }));
} catch (error) {
if (onError) yield put(dispatch({ type: onError, payload: error }));
}
};
};
}
function* watchApi() {
yield takeEvery(actions.sagaApiCallBegan.type, api);
}
const tweetSagas = [fork(watchApi)];
export default tweetSagas;
file - store/tweets.js
import { createSlice } from '@reduxjs/toolkit';
import {
sagaApiCallBegan,
sagaApiCallSuccess,
sagaApiCallFailed,
} from './action/saga';
import { webSocketCallBegan, webSocketCallFailed } from './action/websocket.js';
import { normalize } from 'normalizr';
import { tweetSchema } from '../store/Schema/tweet.js';
const initialState = () => ({
byTweetId: {},
byUserId: {},
allTweetIds: [],
});
// action, actionTypes and reducer
const slice = createSlice({
name: 'tweets',
initialState: initialState(),
// reducers
reducers: {
tweetAdded: (state, action) => {
const { entities, result } = normalize(action.payload, tweetSchema);
Object.assign(state.byTweetId, entities.byTweetId);
Object.assign(state.byUserId, entities.byUserId);
state.allTweetIds.push(result);
},
tweetStoreReseted: (state) => initialState(),
},
});
export const { tweetAdded, tweetStoreReseted } = slice.actions;
export default slice.reducer;
// Action creators
export const fetchTweets = (term) =>
sagaApiCallBegan({
url: `/setsearchterm/${term}`,
method: 'get',
onSuccess: sagaApiCallSuccess.type,
onError: sagaApiCallFailed.type,
});
export const fetchTweetsPause = () =>
sagaApiCallBegan({
url: '/pause',
method: 'GET',
onSuccess: sagaApiCallSuccess.type,
onError: sagaApiCallFailed.type,
});
export const getTweet = (message) =>
webSocketCallBegan({
message: message,
onSuccess: tweetAdded.type,
onError: webSocketCallFailed.type,
});
file - action/saga.js
import { createAction } from '@reduxjs/toolkit';
export const sagaApiCallBegan = createAction('saga/apiCallBegan');
export const sagaApiCallSuccess = createAction('saga/apiCallSuccess');
export const sagaApiCallFailed = createAction('saga/apiCallFailed');
I have been trying to introduce redux-sagas and redux-toolkit to my project. It seems that I am having some wiring problems. Not sure how to fix it. Let me know if you have any ideas. Here is the error I am getting. Here is the link to github
file - configureAppStore.js
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import reducer from './reducer';
import createSagaMiddleware from 'redux-saga';
import tweetSagas from '../saga/tweet.js';
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware];
const middleware = [...getDefaultMiddleware({ thunk: false }), ...middlewares];
const configureAppStore = () => {
// reduxjs/toolkit configureStore enables to dispatch async actions
return configureStore({
reducer: reducer,
middleware: middleware,
});
};
sagaMiddleware.run(tweetSagas);
export default configureAppStore;
file - saga/tweet.js
import { takeEvery, call, put, fork } from 'redux-saga/effects';
import axios from 'axios';
import * as actions from '../store/action/saga.js';
const port = process.env.REACT_APP_PORT;
const hostname = process.env.REACT_APP_LOCALHOST;
const baseURL = `http://${hostname}:${port}`;
function api({ dispatch }) {
return function (next) {
return function* (action) {
if (action.type !== actions.sagaApiCallBegan.type) return next(action);
next(action); // 'sagaApiCallBegan' to show in redux dev tools
const { url, method, onSuccess, onError } = action.payload;
try {
const response = yield call(
async () =>
await axios.request({
baseURL: baseURL,
url,
method,
})
);
if (onSuccess)
yield put(dispatch({ type: onSuccess, payload: response.data }));
} catch (error) {
if (onError) yield put(dispatch({ type: onError, payload: error }));
}
};
};
}
function* watchApi() {
yield takeEvery(actions.sagaApiCallBegan.type, api);
}
const tweetSagas = [fork(watchApi)];
export default tweetSagas;
file - store/tweets.js
import { createSlice } from '@reduxjs/toolkit';
import {
sagaApiCallBegan,
sagaApiCallSuccess,
sagaApiCallFailed,
} from './action/saga';
import { webSocketCallBegan, webSocketCallFailed } from './action/websocket.js';
import { normalize } from 'normalizr';
import { tweetSchema } from '../store/Schema/tweet.js';
const initialState = () => ({
byTweetId: {},
byUserId: {},
allTweetIds: [],
});
// action, actionTypes and reducer
const slice = createSlice({
name: 'tweets',
initialState: initialState(),
// reducers
reducers: {
tweetAdded: (state, action) => {
const { entities, result } = normalize(action.payload, tweetSchema);
Object.assign(state.byTweetId, entities.byTweetId);
Object.assign(state.byUserId, entities.byUserId);
state.allTweetIds.push(result);
},
tweetStoreReseted: (state) => initialState(),
},
});
export const { tweetAdded, tweetStoreReseted } = slice.actions;
export default slice.reducer;
// Action creators
export const fetchTweets = (term) =>
sagaApiCallBegan({
url: `/setsearchterm/${term}`,
method: 'get',
onSuccess: sagaApiCallSuccess.type,
onError: sagaApiCallFailed.type,
});
export const fetchTweetsPause = () =>
sagaApiCallBegan({
url: '/pause',
method: 'GET',
onSuccess: sagaApiCallSuccess.type,
onError: sagaApiCallFailed.type,
});
export const getTweet = (message) =>
webSocketCallBegan({
message: message,
onSuccess: tweetAdded.type,
onError: webSocketCallFailed.type,
});
file - action/saga.js
import { createAction } from '@reduxjs/toolkit';
export const sagaApiCallBegan = createAction('saga/apiCallBegan');
export const sagaApiCallSuccess = createAction('saga/apiCallSuccess');
export const sagaApiCallFailed = createAction('saga/apiCallFailed');
Share
Improve this question
edited Jan 21, 2021 at 8:03
John John
asked Jan 21, 2021 at 5:47
John JohnJohn John
1,5004 gold badges23 silver badges45 bronze badges
1
-
seems like issue with
sagaMiddleware.run(tweetSagas)
can you try removeing that and see if it is working? Essentially you are running the sagas before store is mounted. – Jagrati Commented Jan 21, 2021 at 6:26
3 Answers
Reset to default 3I created and use saga-toolkit that allows async thunks to get resolved by sagas.
slice.js
import { createSlice } from '@reduxjs/toolkit'
import { createSagaAction } from 'saga-toolkit'
const name = 'example'
const initialState = {
result: null,
loading: false,
error: null,
}
export const fetchThings = createSagaAction(`${name}/fetchThings`)
const slice = createSlice({
name,
initialState,
extraReducers: {
[fetchThings.pending]: () => ({
loading: true,
}),
[fetchThings.fulfilled]: ({ payload }) => ({
result: payload,
loading: false,
}),
[fetchThings.rejected]: ({ error }) => ({
error,
loading: false,
}),
},
})
export default slice.reducer
sagas.js
import { call } from 'redux-saga/effects'
import { takeLatestAsync } from 'saga-toolkit'
import API from 'hyper-super-api'
import * as actions from './slice'
function* fetchThings() {
const result = yield call(() => API.get('/things'))
return result
}
export default [
takeLatestAsync(actions.fetchThings.type, fetchThings),
]
I don't see a point to making your store configuration a function, but you should make sure that you are invoking that function in your App.jsx
file. I'm not sure if you are as the code is missing here.
Here are some issues I did find that are pretty easy to fix though.
1 Redux sagas uses Generators
function api
For this function to work it needs to be
function* api
- Prioritize the side effect functions over dispatch
dispatch(put({ ... })
You never need to use dispatch
. Instead use put or the other side effect functions for dispatching events. Put is a blocking dispatch call. So this code should be
Passing put to dispatch will also cause an error in your app as dispatch always expects an object.
yield put({ ... })
- Root sagas are also Generators
const tweetSagas = [fork(watchApi)];
When making a rootSaga, you need to use the yield
keyword in front of the fork
function. A root saga is also a generator function, so this code has to change to the following.
export default function* tweetSagas () {
yield fork(
watchApi()
)
}
You also have to use the yield
keyword in front of your fork function. returning a value from generators with sagas won't do you much good.
Here is the answer
file - configureAppStore.js
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import reducer from './reducer';
import toast from './middleware/toast.js';
import websocket from './middleware/websocket.js';
import createSagaMiddleware from 'redux-saga';
import tweetSagas from '../saga/tweet.js';
const configureAppStore = () => {
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware, websocket, toast];
const middleware = [
...getDefaultMiddleware({ thunk: false }),
...middlewares,
];
const store = configureStore({
reducer: reducer,
middleware: middleware,
});
sagaMiddleware.run(tweetSagas);
return store;
};
export default configureAppStore;
file - saga/tweet.js
import { takeEvery, call, put, fork } from 'redux-saga/effects';
import axios from 'axios';
import * as actions from '../store/action/saga.js';
const port = process.env.REACT_APP_PORT;
const hostname = process.env.REACT_APP_LOCALHOST;
const baseURL = `http://${hostname}:${port}`;
const fetchApi = async ({ baseURL, url, method }) =>
await axios.request({
baseURL: baseURL,
url: url,
method: method,
});
function* api(action) {
const { url, method, onSuccess, onError } = action.payload;
const options = {
baseURL: baseURL,
url: url,
method: method,
};
try {
const response = yield call(fetchApi, options);
if (onSuccess)
yield put({
type: onSuccess,
payload: response.data,
});
} catch (error) {
if (onError) yield put({ type: onError, payload: error });
}
}
function* watchApi() {
yield takeEvery(actions.sagaApiCallBegan.type, api);
}
export default function* tweetSagas() {
yield fork(watchApi);
}
本文标签: javascriptReduxSaga amp ReduxToolkit WiringStack Overflow
版权声明:本文标题:javascript - Redux-Saga & Redux-Toolkit Wiring - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745578645a2664485.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论