javascript - Redux-Saga & Redux-Toolkit Wiring - Stack Overflow

I have been trying to introduce redux-sagas and redux-toolkit to my project. It seems that I am having

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
Add a ment  | 

3 Answers 3

Reset to default 3

I 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
  1. 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({ ... })
  1. 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);
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745578645a4634119.html

相关推荐

  • javascript - Redux-Saga & Redux-Toolkit Wiring - Stack Overflow

    I have been trying to introduce redux-sagas and redux-toolkit to my project. It seems that I am having

    16小时前
    50

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信