In my React application, I use saga middleware. This is my root saga.
import { all } from 'redux-saga/effects';
import alertSaga from 'redux/alert/alert.saga';
export default function* rootSaga() {
console.log('ROOT SAGA')
yield all([
alertSaga(),
]);
}
This is the store.
import { applyMiddleware, createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import { persistStore } from 'redux-persist';
import createSagaMiddleware from 'redux-saga';
import rootReducer from './root-reducer';
import rootSaga from './root-saga';
const INITIAL_STATE = {};
const sagaMiddleware = createSagaMiddleware();
const middleware = [sagaMiddleware];
const store = createStore(
rootReducer,
INITIAL_STATE,
composeWithDevTools(applyMiddleware(...middleware)),
);
sagaMiddleware.run(rootSaga);
const persistor = persistStore(store);
export { store, persistor };
This is my alertSaga.
import { put, takeEvery } from 'redux-saga/effects';
import { IAction } from 'constants/types.constant';
import { removeAlert, setAlert } from 'redux/alert/alert.actions';
import { SET_ALERT } from 'redux/alert/alert.types';
export function* displayAlert({ type, payload }: IAction) {
console.log(type);
console.log(payload);
// yield put(setAlert({ type, payload }));
try {
yield put({ type: SET_ALERT, payload });
} catch (error) {
}
// setTimeout(() => yield put(removeAlert(payload.id), 3000));
}
function* alertSaga() {
console.log('HELLO');
yield takeEvery(SET_ALERT, displayAlert);
}
export default alertSaga;
Finally, this is my alert action.
import { REMOVE_ALERT, SET_ALERT } from './alert.types';
export const setAlert = (payload: Object) => ({ type: SET_ALERT, payload });
export const removeAlert = (payload: number) => ({ type: REMOVE_ALERT, payload });
When the setAlert is dispatched, it doesn't hit to the alert saga. What am I doing wrong here?
if you'd like to export just 1 saga, try below
export default function* alertSaga() {
console.log('HELLO');
yield takeEvery(SET_ALERT, displayAlert);
}
or if you have multiple sagas to export
export default function* yourSagas() {
yield all([
alertSaga(),
otherSaga(),
]);
}
Related
I am trying to store data in my redux store using a reducer when we get data from B/E API and trying to store data in the reducer(store). But not working. My code is correct to me. But somehow it's not working.
My Store:-
import createSagaMiddleware from 'redux-saga';
import { configureStore } from '#reduxjs/toolkit';
import rootReducer from './rootReducer';
import rootSaga from './rootsaga';
// saga middleware
const sagaMiddleware = createSagaMiddleware();
// redux store
const store = configureStore({
reducer: rootReducer,
middleware: [sagaMiddleware],
});
// run saga middleware
sagaMiddleware.run(rootSaga);
export default store;
My root saga:-
import { all, takeEvery } from '#redux-saga/core/effects';
import * as categoryActionTypes from '../redux/types/categoryActionTypes';
import * as productActionTypes from '../redux/types/productActionTypes';
import { getAllStudents } from './sagas/categorySaga';
import { getAllProductWatcher } from './sagas/productSaga';
export default function* root() {
yield all([
takeEvery(categoryActionTypes.GET_ALL_CATEGORY, getAllStudents),
takeEvery(productActionTypes.GET_ALL_PRODUCT_ACTION, getAllProductWatcher),
]);
}
My Reducer:- (console.log() not working) That's means not store data into reducer
import * as actionTypes from '../types/productActionTypes';
const initialState = {
product: [],
isLoading: true,
error: true,
};
// reducer
export default function productReducer(state = initialState, action) {
switch (action.types) {
case actionTypes.GET_ALL_PRODUCT_SUCCESS:
console.log(action.data);
return {
...state,
product: action.data,
isLoading: false,
error: false,
};
default:
return state;
}
}
This is my saga method and this is how I store data into my reducer:-
import { put } from '#redux-saga/core/effects';
import { GET_ALL_PRODUCT_SUCCESS } from '../types/productActionTypes';
import { createRequest } from '#utils/create-request';
export function* getAllProductWatcher(upload) {
try {
const Axios = yield createRequest(upload);
const res = yield Axios.get('http://localhost:8080/product');
if (res) {
**//Tying to store API data to my reducer**
yield put({
type: GET_ALL_PRODUCT_SUCCESS,
data: res.data,
});
}
} catch (e) {
console.log(e);
}
}
I really need your help... Thanks.
I started doing the typing of my redux and ran into such a problem, namely the typing of useSelector
Here is the hook I'm creating:
import {TypedUseSelectorHook, useSelector} from 'react-redux'
import {RootState} from '../store/create-reducer'
export const UseTypedSelector: TypedUseSelectorHook <RootState> = useSelector
And he returns me an error:
screen
How to solve this problem? For the second day I can't get off the ground, and using useSelector ((state: any) => state? .SESSION) is not an option.
Here is my side:
create-reducer:
import { combineReducers } from 'redux'
import { STATE } from '../session/types'
import { reducer } from '../session/reducers'
const rootReducer = (asyncReducers: object) => {
return (
combineReducers({
...asyncReducers,
[STATE]: reducer,
})
)
}
export default rootReducer
export type RootState = ReturnType<typeof rootReducer>
create-store:
import { applyMiddleware, compose, createStore } from 'redux'
import thunk from 'redux-thunk'
import persistStore from './persist-store'
import persistReducer from './persist-reducer'
const store = (initialState = {}) => {
const middlewares = [thunk]
const enhancers: Array<any> = []
const store = createStore(
persistReducer({}),
initialState,
compose(applyMiddleware(...middlewares), ...enhancers),
)
const persistor = persistStore(store)
return { store, persistor }
}
export default store
index:
export { default as createReducer } from './create-reducer'
export { default as createStore } from './create-store'
export { default as persistReducer } from './persist-reducer'
persist-reducer:
import { persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import createReducer from './create-reducer'
const persistConfig = { key: 'myproject', storage, whitelist: ['session'] }
const reducer = (asyncReducers: any) => persistReducer(persistConfig, createReducer(asyncReducers))
export default reducer
persist-store:
import { persistStore } from 'redux-persist'
const store = (store: any) => persistStore(store, null, () => {})
export default store
I have set up my redux store and everything seems alright all imports and exports seems correct to me but I do not seem to have a valid reducer and sagas. Been stuck, what am I doing wrong?
I get this error message
I have a store with the file structure below
Store
configStore.js
index.js
import { applyMiddleware, compose, createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from '../components/rootReducer';
export default function configureStore(initialState) {
const sagaMiddleware = createSagaMiddleware();
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
return {
...createStore(
rootReducer,
initialState,
composeEnhancers(applyMiddleware(sagaMiddleware)),
),
runSaga: sagaMiddleware.run,
};
}
import configureStore from './configStore';
import rootSaga from '../components/rootSaga';
const store = configureStore({});
store.runSaga(rootSaga);
export default store;
rootSaga
import { all } from 'redux-saga/effects';
import planets from './planets';
export default function* rootSaga() {
yield all([
planets.sagas(),
]);
}
rootReducer
import { combineReducers } from 'redux';
import planets from './planets';
export default combineReducers({
planets: planets.reducers,
});
In my components I have
reducers.js
import { UPDATE_PLANETS, LOAD_PLANETS } from './actionTypes';
const initialState = {
isPlanetsLoading: false,
planets: [],
};
export default (state = initialState, { type, payload }) => {
switch (type) {
case LOAD_PLANETS:
return {
...state,
isPlanetsLoading: true,
};
case UPDATE_PLANETS:
return {
...state,
isPlanetsLoading: false,
planets: payload,
};
default:
return state;
}
};
Planets.js
import { List } from "antd";
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { requestPlanets } from '../actions';
const Planets = () => {
const dispatch = useDispatch();
const { planets } = useSelector(
(state) => state.planets
);
console.log(planets);
useEffect(() => {
dispatch(requestPlanets());
}, [dispatch, planets]);
// return statement
};
export default Planets;
createStore returns the store. So don't spread it. Just associate the output of createStore to an object property say store.
in index.js, destructure the configStore object { store, runSaga }
configStore
export default function configureStore(initialState) {
const sagaMiddleware = createSagaMiddleware();
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
return {
store: createStore(
rootReducer,
initialState,
composeEnhancers(applyMiddleware(sagaMiddleware)),
),
runSaga: sagaMiddleware.run,
};
}
index.js
import configureStore from './configStore';
import rootSaga from '../components/rootSaga';
const { store, runSaga } = configureStore({});
runSaga(rootSaga);
export default store;
Can't stop infinity loop client error like: https://imgur.com/34BSVu0
This error just typo.
But saga action is repeated endless times.
When I tried without saga, I got only one time error. (Not endless)
I made sandbox: https://codesandbox.io/s/blissful-pine-qvcyv?from-embed
saga:
import { call, put, takeLatest } from 'redux-saga/effects';
function* fetchSome(action: Action) {
try {
const { id } = action.payload;
const { data } = yield call(api, { id });
yield put(fetchSomeSucess({ data }));
} catch (e) {
yield put(fetchSomeFailure(e));
}
}
export function* someProcess() {
yield takeLatest('FETCH_SOME', fetchSome);
}
store:
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { rootReducer } from '../reducers';
import { rootSaga } from '../sagas';
const sagaMiddleware = createSagaMiddleware();
export const runSaga = async () => {
return sagaMiddleware.run(rootSaga);
};
export const configureStore = (initialState: Object = {}) => {
const store = createStore(
rootReducer,
initialState,
applyMiddleware(sagaMiddleware),
);
runSaga();
return store;
};
rootSaga:
import { all, fork } from 'redux-saga/effects';
export function* rootSaga() {
yield all([
fork(someProcess),
]);
}
Make sure your action creators are using the right constants. In this file:
function* fetchSome(action: Action) {
try {
const { id } = action.payload;
const { data } = yield call(api, { id });
yield put(fetchSomeSucess({ data }));
} catch (e) {
yield put(fetchSomeFailure(e));
}
}
You need to make sure that the fetchSomeSucess() and fetchSomeFailure() action creators are not creating an action with type: FETCH_SOME which could easily be a typo.
If either of those have type: FETCH_SOME it would continually call your saga creating an endless loop
I've created a react app using create-react-app and react-redux. I dispatch an action using mapDispatchToProps on clicking a button and it returns a payload. But when I try to retrieve the props using mapStateToProps in my component, it returns the initial state.
What am I doing wrong?
I have tried to debug thoroughly and I realize that the action is dispatched and the payload makes it to the action creator. But the reducer isn't triggered after the action is dispatched.
It might be how I am calling it or how I have set up my reducer as well.
index.js file:
import React from 'react';
import './css/index.css';
import App from './App/App';
import * as serviceWorker from './serviceWorker';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './reducers';
import thunk from 'redux-thunk';
const store = createStore(rootReducer, applyMiddleware(thunk));
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
reducers/Reducer.js
reducers/Reducer.js
import { GET_RESP } from '../modules/actions'
function getInitialState () {
return {
predictions: [],
score: null
}
}
function gesResp (state, payload) {
return {
...state,
predictions: payload.predictions,
score: payload.score
}
}
export function Reducer (state, action) {
if (!state) {
return getInitialState();
}
switch(action.type) {
case GET_RESP:
return gesResp(state, action.payload);
default:
return state;
}
}
export default Reducer;
reducers/index.js
import { combineReducers } from 'redux';
import Reducer from './Reducer'
const rootReducer = combineReducers({
Reducer
});
export default rootReducer;
action.js
import axios from 'axios';
// actions:
export const GET_RESP = 'GET_RESP';
// action creators:
export function gesResp (payload) {
return {
type: GET_RESP,
payload: payload
}
}
export function fetchRecommendations (description, resp) {
let url = 'myendpointurl';
let requestPayload = {
description: description,
resp: resp
}
return (dispatch) => {
return axios.post(url, requestPayload)
.then(function(res) {
gesResp(res.data);
})
}
}
component file: (I'm only posting related code):
handleSubmit () {
this.props.fetchMyRecommendations(Desc,
this.state.htmlContent);
}
const mapStateToProps = state => {
return {
predictions: state.Reducer.predictions,
score: state.Reducer.score
};
}
const mapDispatchToProps = dispatch => {
return {
fetchMyRecommendations: (Desc, userScore) =>
dispatch(fetchRecommendations(Desc, userScore))
};
}
export default connect(mapStateToProps, mapDispatchToProps)
(HomePage);
Ideally what I want is in the mapStateToProps to return the predictions array and the resp score.
I can see that they are being returned in the network call and showing up the actions call as well. Thanks in advance to whoever can help! :)
You need to dispatch getReccommendations to actually trigger the reducer for your asynchronous action. Try the following:
export function fetchRecommendations (job_description, resume) {
let url = 'myendpointurl';
let requestPayload = {
job_description: job_description,
resume: resume
};
return (dispatch) => {
return axios.post(url, requestPayload)
.then(function(res) {
dispatch(getReccommendations(res.data));
});
}
}
Hopefully that helps!