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
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 am trying to send a GET request using axios and React Saga.
The request fired twice
This is my component file where I call the getBusinessHoursList action:
import { getBusinessHoursList } from "../../../../redux/actions";
...
...
componentDidMount() {
this.props.getBusinessHoursList(this.state.id);
}
...
...
const mapStateToProps = ({ settings }) => {
return {
settings
};
};
export default connect(
mapStateToProps,
{
getBusinessHoursList,
}
)(injectIntl(BusinessHours));
This is my service file where I use axios to get my business hours list:
setting-service.js:
import axios from '../util/api';
import { configureStore } from '../redux/store';
export const settingsService =
{
getBusinessHours,
};
function getBusinessHours() {
const store = configureStore({});
const user = JSON.parse(store.getState().authUser.user)
return axios.get("business/" + user.business.id + "/businesshours")
.then(response => {
return response.data.data
}).catch(error => {
return error.response.data
})
}
This is actions file where I define the actions
actions.js:
import {
CHANGE_LOCALE,
SETTING_GET_BUSINESS_HOURS_FAIL,
SETTING_GET_BUSINESS_HOURS_SUCCESS,
SETTING_GET_BUSINESS_HOURS,
} from '../actions';
export const getBusinessHoursList = (data) => ({
type: SETTING_GET_BUSINESS_HOURS,
payload: data
});
export const getBusinessHoursSuccess = (items) => ({
type: SETTING_GET_BUSINESS_HOURS_SUCCESS,
payload: items
});
export const getBusinessHoursFail = (error) => ({
type: SETTING_GET_BUSINESS_HOURS_FAIL,
payload: error
});
reducer.js
import {
CHANGE_LOCALE,
SETTING_GET_BUSINESS_HOURS,
SETTING_GET_BUSINESS_HOURS_FAIL,
SETTING_GET_BUSINESS_HOURS_SUCCESS
} from '../actions';
const INIT_STATE = {
errors: '',
loadingBH: false,
businessHoursItems: null
};
export default (state = INIT_STATE, action) => {
switch (action.type) {
case SETTING_GET_BUSINESS_HOURS:
return { ...state, loadingBH: false };
case SETTING_GET_BUSINESS_HOURS_SUCCESS:
return { ...state, loadingBH: true, businessHoursItems: action.payload};
case SETTING_GET_BUSINESS_HOURS_FAIL:
return { ...state, loadingBH: true, errors: action.payload };
default: return { ...state };
}
}
saga.js:
import { all, call, fork, put, takeEvery, takeLatest, take } from "redux-saga/effects";
import { getDateWithFormat } from "../../helpers/Utils";
import { settingsService } from '../../services/settings-service'
import {
SETTING_GET_BUSINESS_HOURS,
SETTING_UPDATE_BUSINESS_HOURS,
} from "../actions";
import axios from "../../util/api";
import { NotificationManager } from "../../components/common/react-notifications";
import {
getBusinessHoursSuccess,
getBusinessHoursFail,
} from "./actions";
const getServiceListRequest = async () =>
await settingsService.getBusinessHours()
.then(authUser => authUser)
.catch(error => error);
function* getBusinessHours() {
console.log('test')
try {
const response = yield call(getServiceListRequest);
yield put(getBusinessHoursSuccess(response));
} catch (error) {
yield put(getBusinessHoursFail(error));
}
}
export function* watchGetBusinessHours() {
yield takeLatest(SETTING_GET_BUSINESS_HOURS, getBusinessHours);
}
export default function* rootSaga() {
yield all([
fork(watchGetBusinessHours),
]);
}
Global sagas file : sagas.js:
import { all } from 'redux-saga/effects';
import authSagas from './auth/saga';
import settingsSagas from './settings/saga';
export default function* rootSaga(getState) {
yield all([
authSagas(),
settingsSagas(),
]);
}
The request fired successfully and I get Business hours list but the request fired twice
I tried to use takeLatest in place of takeEvery
This is the network tab
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(),
]);
}
I'm sorry if my code is extremely amateur. I just recently started working with react-redux and javascript. I feel like I am a bit spaced out when looking at tutorials when it comes to visualizing states and what the store does. So I'm trying to code something to visually see it in code. My code is similar to the default preloaded code from Visual Studio when a new project for ASP.NET Web app w/ react-redux is created. I want to just call an API using redux and pass that information to the page.
For what I've got right now, I noticed that my API is not called, as putting a red light on my actionCreator is not reached.
///////////File 1 CreaterAction and Reducer/////////////////
const requestEvents = 'REQUEST_EVENTS';
const recieveEvents = 'RECEIVE_EVENTS';
const initialState = { events: [], isLoading: false };
async function getData(url) {
const response = await fetch(url);
return response.json();
}
export const actionCreators = {
requestEvents: () => async (dispatch) => {
dispatch({ type: requestEvents});
const url = 'api\stuff';
const events = await getData(url);
dispatch({ type: recieveEvents, events });
}
};
export const reducer = (state, action) => {
state = state || initialState;
if (action.type === requestEvents) {
return {
...state,
events: action.events,
isLoading: true
};
}
return state;
};
//////////////File 2 My Actual component//////////////////
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { actionCreators } from '../store/file1';
class Events extends Component {
componenetDidMount() {
this.ensureDataFetched();
}
ensureDataFetched() {
const stuff = this.props.//!!!! Does not show .requestEvents
}
render() {
return (
<div>
<h1>Events</h1>
<p>This component demonstrates fetching data from the server and working with URL parameters.</p>
{renderData(this.props)}
</div>
);
}
}
function renderData(props) {
return (
<p>{props.events}</p>
);
}
export default connect(
state => state.events,
dispatch => bindActionCreators(actionCreators, dispatch)
)(Events);
///////////////FILE 3 Config Store//////////////////
import { applyMiddleware, combineReducers, compose, createStore } from 'redux';
import thunk from 'redux-thunk';
import { routerReducer, routerMiddleware } from 'react-router-redux';
import * as Counter from './Counter';
import * as file1 from './file1';
export default function configureStore (history, initialState) {
const reducers = {
events: file1.reducer
};
const middleware = [
thunk,
routerMiddleware(history)
];
// In development, use the browser's Redux dev tools extension if installed
const enhancers = [];
const isDevelopment = process.env.NODE_ENV === 'development';
if (isDevelopment && typeof window !== 'undefined' && window.devToolsExtension) {
enhancers.push(window.devToolsExtension());
}
const rootReducer = combineReducers({
...reducers,
routing: routerReducer
});
return createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middleware), ...enhancers)
);
}
It runs just shows
Events
This component demonstrates fetching data from the server and working with URL parameters.
My guess is that it's because I haven't used/called this.props.requestEvents
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!