I'm trying to show a list of recipes from an API in my component when a form submitted. It doesn't show any result in the component and doesn't have any error!
May somebody help me , What's wrong with my code ?
here is my action.js
import { getDataConstants } from "../_constants";
import { getDataService } from "../_service";
export const getDataAction = {
fetchRecipes
}
function fetchRecipes(query) {
return dispatch => {
dispatch(loading());
getDataService.fetchRecipes(query).then(
response => {
dispatch(success(response));
},
error =>{
dispatch(failed(error));
}
)
}
function loading() { return { type: getDataConstants.FETCH_RECIPES_LOADING }; }
function success(data) { return { type: getDataConstants.FETCH_RECIPES_SUCCESS, data }; }
function failed(error) { return { type: getDataConstants.FETCH_RECIPES_FAILED, error }; }
}
code for reducer.js
import { getDataConstants } from "../_constants";
const initialState = {
loading: false,
items: [],
error: null
};
export function getDataReducer(state = initialState, action) {
switch (action.type) {
case getDataConstants.FETCH_RECIPES_LOADING:
return {
...state,
loading: true,
error: null,
items: []
};
case getDataConstants.FETCH_RECIPES_SUCCESS:
return {
...state,
loading: false,
items: action.payload
};
case getDataConstants.FETCH_RECIPES_FAILED:
return {
...state,
loading: false,
error: action.payload,
items: []
};
default:
return state;
}
}
export const getRecipes = state => state.items;
export const getRecipesloading = state => state.loading;
export const getRecipesError = state => state.error;
I fetch data in the service.js component
code for service.js
import {TIMEOUT_DELAY,HOST} from '../_constants';
import axios from 'axios';
export const getDataService = {
fetchRecipes
}
async function fetchRecipes(query) {
let timeout = null;
try{
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
timeout = setTimeout(()=>{source.cancel()},TIMEOUT_DELAY);
debugger
const response = await axios({
url: `${HOST}?apiKey=94be430aadf644f6a8c8c95abbcce4c1&query=${query}&_number=12`,
method: "get",
headers: { "content-type": "application/json" },
cancelToken: source.token
});
if (response.status === 200) {
if (timeout) clearTimeout(timeout);
return response.data;
} else {
if (timeout) clearTimeout(timeout);
return Promise.reject({isTimeout:false,error: response.data});
}
}catch (error) {
if (timeout) clearTimeout(timeout);
if (axios.isCancel(error)) {
return Promise.reject({isTimeout:true});
} else {
return Promise.reject({isTimeout:false,error});
}
}
}
code for Recipes component where API response data shown
const Recipes = props => {
const { dispatch, error, loading, items } = props;
const classes = useStyles();
const [query, setQuery] = useState("beef");
const submitHandler = async event => {
event.preventDefault();
dispatch(getDataAction.fetchRecipes(query));
};
const handleChange = event => {
setQuery(event.target.value);
};
return (
<>
<form onSubmit={submitHandler} className={classes.formWidth}>
<input
type="text"
value={query}
onChange={handleChange}
className={classes.input}
/>
</form>
{error && <div>Something went wrong ...</div>}
{loading ? (
<div>
<img src={Loading} alt="Loading" />
</div>
) : (
<ul className={classes.centeredDiv}>
{items &&
items.results.map(recipe => (
<li
className={classes.media}
image={`${imgUrl}${recipe.image}`}
title={recipe.title}
/>
))}
</ul>
)}
}
</>
);
}
const mapStateToProps = state => {
return {
loading: getRecipesloading(state),
items: getRecipes(state),
error: getRecipesError(state)
};
};
Sorry about the large amount of code dumped, its just all related and I believe the error lies somewhere.
Your reducer expects action.payload but instead you send action.data. It should be:
case getDataConstants.FETCH_RECIPES_SUCCESS:
return {
...state,
loading: false,
items: action.data
}
You should update your success and failed functions like so:
function success(data) {
return {
type: getDataConstants.FETCH_RECIPES_SUCCESS,
payload: data
};
}
function failed(error) {
return {
type: getDataConstants.FETCH_RECIPES_FAILED,
payload: error
};
}
To avoid such typo problems you can create default action creator:
function createAction(type, payload, meta) {
return {
type: type,
payload: payload,
meta: meta
};
}
// usage
function success(data) {
return createAction(getDataConstants.FETCH_RECIPES_SUCCESS, data)
}
Related
I know this question has been asked multiple times but I cannot seem to find an answer. I have a component named DynamicTable which renders JSON as a data table. It has been tested in multiple other pages and works correctly. Here I have put it into a React-Bootstrap tab container. The data pull works correctly but the page is not re-rendering when the fetch is complete.
Here is the code I am using
//RetailRequests.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import FormComponent from '../Elements/FormComponent';
import TabContainer from 'react-bootstrap/TabContainer';
import Tabs from 'react-bootstrap/Tabs';
import Tab from 'react-bootstrap/Tab';
import DynamicTable from '../Elements/DynamicTable';
const mapStateToProps = (state) => {
return {
RequestData: state.RetailRequests,
siteMap: state.siteMap
}
}
const mapDispatchToProps = (dispatch) => {
return {
Retail_Request_Fetch: () => { return dispatch(Retail_Request_Fetch()) },
Retail_Request_Insert: (data) => { return dispatch(Retail_Request_Insert(data)) },
Retail_Request_Delete: (id) => { return dispatch(Retail_Request_Delete(id)) },
Retail_Request_DeleteAll: () => { return dispatch(Retail_Request_DeleteAll()) }
}
}
class RetailRequests extends Component {
constructor(props) {
super(props);
var roles = props.siteMap.siteMapData.userRoles.toLowerCase();
this.state = {
showAdmin: roles.indexOf('admin') >= 0 || roles.indexOf('systems') >= 0
}
}
componentDidMount() {
this.props.Retail_Request_Fetch();
}
// ...
render() {
let rows = this.buildData();
let data = this.props.RequestData?this.props.RequestData.adminData:null;
return (
<div style={{ transform: 'translateY(10px)' }} >
<TabContainer>
<div className='col-md-10 offset-1' >
<Tabs defaultActiveKey='general' id='retail_reports_tab_container' >
<Tab eventKey='general' title='Enter New Request'>
<h1> Retail Requests</h1>
<FormComponent rows={rows} submit={this.submitFn} />
</Tab>
<Tab eventKey='admin' title='Admin' disabled={!this.state.showAdmin}>
<h1>Manager Data</h1>
<DynamicTable
data={data}
border="solid 1px black"
title={"Retail Requests Admin"}
/>
</Tab>
</Tabs>
</div>
</TabContainer>
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(RetailRequests);
//RetailRequestsCreator.js
export const Retail_Request_Fetch = () => (dispatch, getState) => {
var init = JSON.parse(JSON.stringify(fetchInit()));//copy to not modify the original
var myReq = new Request(`${process.env.REACT_APP_HOST}/Retail_Request`, init);
dispatch({
type: ActionTypes.REQUESTS_LOADING
})
return fetch(myReq)
.then((response) => {
if (response.ok) {
return response;
}
else {
var error = new Error("Error " + response.statusText);
error.response = response;
throw error;
}
}, (error) => {
var err = new Error(error.message);
throw err;
})
.then((response) => { return response.json() })
.then((RequestData) => {
if (RequestData !== "False") {
console.log(RequestData)
dispatch({
type: ActionTypes.REQUESTS_LOADED,
payload: RequestData
})
}
else CurrentPage_Update({ componentId: 'NotAllowed' });
})
.catch((err) => {
dispatch({
type: ActionTypes.REQUESTS_FAILED,
payload: "Error: " + err.message
})
});
}
//RetailRequestReducer.js
import * as ActionTypes from '../ActionTypes';
export const retailRequests = (state = {
isLoading: true,
errMess: null,
currentPage: []
}, action) => {
switch (action.type) {
case ActionTypes.REQUESTS_LOADED:
return { ...state, isLoading: false, errMess: null, adminData: action.payload };
case ActionTypes.REQUESTS_LOADING:
return { ...state, isLoading: true, errMess: null, adminData: {} };
case ActionTypes.REQUESTS_FAILED:
return { ...state, isLoading: false, errMess: action.payload, adminData: null };
default:
return state;
}
}
I am sure that there is something simple in this but the only error I am getting is that the data I am using, this.props.RequestData, is undefined although after the fetch I am getting proper state change in Redux.
It looks like you have problem in mapStateToProps
const mapStateToProps = (state) => {
return {
RequestData: state.retailRequests, // use lower case for retailRequests instead of RetailRequests
siteMap: state.siteMap
}
}
I have wriiten the below code in which the city the alert function initially works fine when a wrong city name or no city name is entered. But after the Weather details are displayed here again when I click on submit then it re renders the previous state and new one and gives both result.
Code:
import React, { FC, useState, FormEvent } from "react";
import { useDispatch } from "react-redux";
import { Header, Input, Button } from "../style";
import {
getWeather,
setLoading
} from "../../store/actions/WeatherAction/weatherActions";
import { setAlert } from "../../store/actions/AlertAction/alertActions";
interface SearchProps {
title: string;
}
const Search: FC<SearchProps> = ({ title }) => {
const dispatch = useDispatch();
const [city, setCity] = useState("");
const changeHandler = (e: FormEvent<HTMLInputElement>) => {
setCity(e.currentTarget.value);
};
const submitHandler = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
dispatch(setLoading());
dispatch(getWeather(city));
setCity("");
};
return (
<>
<Header>
{title}
<form onSubmit={submitHandler}>
<Input
type="text"
placeholder="Enter city name"
value={city}
onChange={changeHandler}
/>
<br />
<Button>Search</Button>
</form>
</Header>
</>
);
};
export default Search;
weatherAction.ts
import { ThunkAction } from "redux-thunk";
import { RootState } from "../..";
import {
WeatherAction,
WeatherData,
WeatherError,
GET_WEATHER,
SET_LOADING,
SET_ERROR
} from "../../types";
export const getWeather = (
city: string
): ThunkAction<void, RootState, null, WeatherAction> => {
return async (dispatch) => {
try {
const res = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=3020950b62d2fb178d82816bad24dc76`
);
if (!res.ok) {
const resData: WeatherError = await res.json();
throw new Error(resData.message);
}
const resData: WeatherData = await res.json();
dispatch({
type: GET_WEATHER,
payload: resData
});
} catch (err) {
dispatch({
type: SET_ERROR,
payload: err.message
});
}
};
};
export const setLoading = (): WeatherAction => {
return {
type: SET_LOADING
};
};
export const setError = (): WeatherAction => {
return {
type: SET_ERROR,
payload: ""
};
};
weatherReducer
import {
WeatherState,
WeatherAction,
GET_WEATHER,
SET_LOADING,
SET_ERROR
} from "../../types";
const initialState: WeatherState = {
data: null,
loading: false,
error: ""
};
export default (state = initialState, action: WeatherAction): WeatherState => {
switch (action.type) {
case GET_WEATHER:
return {
data: action.payload,
loading: false,
error: ""
};
case SET_LOADING:
return {
...state,
loading: true
};
case SET_ERROR:
return {
...state,
error: action.payload,
loading: false
};
default:
return state;
}
};
The problem is that your reducer does not clear the weather data when processing a SET_ERROR action. If you want to clear the weather data when you receive an error, you should set data back to null like this:
case SET_ERROR:
return {
data: null,
error: action.payload,
loading: false
};
I've been debugging why my state hasn't been changing and noticed this being logged in my reducer:
{ type: '##redux/INITi.8.g.w.a.m' }
This is the store which includes state, action types, reducer, actions:
/* initial state */
import axios from 'axios';
export var usersStartState = {
accountNotVerified: null,
isLoggedIn: false,
error: true,
userAvatar: 'uploads/avatar/placeholder.jpg'
};
/* action types */
export const actionTypes = {
RESET_USER_ACCOUNT_IS_VERIFIED: 'RESET_USER_ACCOUNT_IS_VERIFIED',
USER_ACCOUNT_IS_VERIFIED: 'USER_ACCOUNT_IS_VERIFIED',
USER_ACCOUNT_NOT_VERIFIED: 'USER_ACCOUNT_NOT_VERIFIED',
IS_LOGGED_IN: 'IS_LOGGED_IN',
IS_LOGGED_OUT: 'IS_LOGGED_OUT',
LOAD_USER_AVATAR: 'LOAD_USER_AVATAR',
ERROR_LOADING: 'ERROR_LOADING' // LOAD_MULTER_IMAGE: "LOAD_MULTER_IMAGE"
};
/* reducer(s) */
export default function users(state = usersStartState, action) {
console.log('In users reducer! ', action);
switch (action.type) {
case actionTypes.RESET_USER_ACCOUNT_IS_VERIFIED:
return Object.assign({}, state, { accountNotVerified: null });
case actionTypes.USER_ACCOUNT_IS_VERIFIED:
return Object.assign({}, state, { accountNotVerified: false });
case actionTypes.USER_ACCOUNT_NOT_VERIFIED:
return Object.assign({}, state, { accountNotVerified: true });
case actionTypes.IS_LOGGED_IN:
return Object.assign({}, state, { isLoggedIn: true });
case actionTypes.IS_LOGGED_OUT:
return Object.assign({}, state, { isLoggedIn: false });
case actionTypes.LOAD_USER_AVATAR:
return { ...state, userAvatar: action.data };
case actionTypes.ERROR_LOADING:
return Object.assign({}, state, { error: true });
default:
return state;
}
}
/* actions */
export const resetUserAcoountVerified = () => {
return { type: actionTypes.RESET_USER_ACCOUNT_IS_VERIFIED };
};
export const userHasBeenVerified = () => {
return { type: actionTypes.USER_ACCOUNT_IS_VERIFIED };
};
export const userHasNotBeenVerified = () => {
return { type: actionTypes.USER_ACCOUNT_NOT_VERIFIED };
};
export const logInUser = () => {
return { type: actionTypes.IS_LOGGED_IN };
};
export const logOutUser = () => {
axios
.get('/users/logout')
.then(response => {
if (response.status === 200) {
console.log('You have been logged out!');
}
})
.catch(function(error) {
if (error.response.status === 500) {
console.log('An error has occured');
}
});
return { type: actionTypes.IS_LOGGED_OUT };
};
export const loadAvatar = data => {
console.log('in load avatar ', data);
return { type: actionTypes.LOAD_USER_AVATAR, data: data };
};
export const errorLoading = () => {
return { type: actionTypes.ERROR_LOADING };
};
And this is my component:
import { useState } from 'react';
import { Card, Icon, Image, Segment, Form } from 'semantic-ui-react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { loadAvatar } from '../../store/reducers/users/index';
import axios from 'axios';
function ImageUploader({ userAvatar }) {
var [localUserAvatar, setLocalUserAvatar] = useState(userAvatar);
function fileUploader(e) {
e.persist();
var imageFormObj = new FormData();
imageFormObj.append('imageName', 'multer-image-' + Date.now());
imageFormObj.append('imageData', e.target.files[0]);
loadAvatar('foo');
axios({
method: 'post',
url: `/users/uploadmulter`,
data: imageFormObj,
config: { headers: { 'Content-Type': 'multipart/form-data' } }
})
.then(data => {
if (data.status === 200) {
console.log('data ', data);
console.log('path typeof ', typeof data.data.path);
loadAvatar('foo');
setLocalUserAvatar('../../' + data.data.path);
}
})
.catch(err => {
alert('Error while uploading image using multer');
});
}
Here are
console.log('userAvatar in imageUploader ', userAvatar);
console.log('Date.now() line 44 in imageUploader ', Date.now());
console.log('localUserAvatar in imageUploader ', localUserAvatar);
console.log('Date.now() line 46 in imageUploader ', Date.now());
console.log("loadAvatar('barbar') ", loadAvatar('barbar'));
return (
<>
<Segment>
<Card fluid>
<Image src={localUserAvatar} alt="upload-image" />
<Segment>
<Form encType="multipart/form-data">
<Form.Field>
<input
placeholder="Name of image"
className="process__upload-btn"
type="file"
content="Edit your Avatar!"
onChange={e => fileUploader(e)}
/>
</Form.Field>
</Form>
</Segment>
<Card.Content>
<Card.Header>Charly</Card.Header>
<Card.Meta>
<span className="date">Joined in 2015</span>
</Card.Meta>
<Card.Description>Charly</Card.Description>
</Card.Content>
<Card.Content extra>
<a>
<Icon name="user" />
22 Friends
</a>
</Card.Content>
</Card>
</Segment>
</>
);
}
function mapStateToProps(state) {
const { users } = state;
const { userAvatar } = users;
return { userAvatar };
}
const mapDispatchToProps = dispatch => bindActionCreators({ loadAvatar }, dispatch);
export default connect(
mapStateToProps,
mapDispatchToProps
)(ImageUploader);
From the logs you can see loadAvatar the dispatcher, gets fired in the component and in the store...
But the state in the store never changes....
Also other states do change correctly...Like for example I have a Modal and that updates nicely.
Any help would be appreciated as what { type: '##redux/INITi.8.g.w.a.m' } and why my state is not updating?
Redux dispatches that action as an internal initialization step:
// When a store is created, an "INIT" action is dispatched so that every
// reducer returns their initial state. This effectively populates
// the initial state tree.
dispatch({ type: ActionTypes.INIT })
It's specifically so that your reducers will see the action, not recognize the action type, and return their default state, thus defining the initial overall app state contents.
I have an API endpoint that returns a list of users in an 'application/stream+json' type response. The items are separated by a new line character.
Example data can be seen here.
Component
class UserList extends Component {
componentDidMount() {
const { fetchUsers } = this.props;
fetchUsers();
}
render() {
const { isFetching = false, users = [] } = this.props;
if (isFetching) {
return <Loader message="Users are loading..." />;
}
if (!users || users.length === 0) {
return 'No users found.';
}
const children = users
.map(user => <UserListItem key={user.id} user={user} />);
return (
<div className="UserList">
<Paper>
<List>
<Subheader>Users</Subheader>
{children}
</List>
</Paper>
</div>
);
}
}
UserList.propTypes = {
users: PropTypes.arrayOf(PropTypes.any),
isFetching: PropTypes.bool.isRequired,
fetchUsers: PropTypes.func.isRequired,
};
UserList.defaultProps = {
users: [],
};
function mapStateToProps(state) {
const { users, isFetching } = state.users;
return {
users,
isFetching,
};
}
function mapDispatchToProps(dispatch) {
return {
fetchUsers: bindActionCreators(actions.fetchUsers, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(UserList);
Reducer
const initialState = {
users: [],
isFetching: false,
};
function fetchUsers(state) {
return {
...state,
isFetching: true,
};
}
function fetchUsersItemReceived(state, action) {
const { user } = action;
return {
...state,
users: [...state.users, user],
isFetching: false,
};
}
export default function (state = initialState, action) {
switch (action.type) {
case actionTypes.FETCH_USERS_REQUEST:
return fetchUsers(state);
case actionTypes.FETCH_USERS_ITEM_RECEIVED:
return fetchUsersItemReceived(state, action);
default:
return state;
}
}
Action (the parser is the Streaming JSON Parser found here)
export function fetchUsers() {
return {
type: actionTypes.FETCH_USERS_REQUEST,
};
}
function fetchUsersItemReceived(user) {
return {
type: actionTypes.FETCH_USERS_ITEM_RECEIVED,
user,
};
}
function fetchUsersSuccess() {
return {
type: actionTypes.FETCH_USERS_SUCCESS,
};
}
function fetchUsersFailure(error) {
return {
type: actionTypes.FETCH_USERS_FAILURE,
error,
};
}
function getJsonStream(url) {
const emitter = new Subject();
const req$ = RxHR
.get(url)
.flatMap(resp => resp.body)
.subscribe(
(data) => {
parser.write(data);
parser.onValue = (value) => {
if (!parser.key) {
emitter.next(value);
}
};
},
err => emitter.error(err),
() => emitter.complete(),
);
return emitter;
}
export const fetchUsersEpic = action$ =>
action$.ofType(actionTypes.FETCH_USERS_REQUEST)
.concatMap(() => getJsonStream(`${api.API_BASE_URL}/user`))
.map(user => fetchUsersItemReceived(user));
configureStore.js
const logger = createLogger();
const epicMiddleware = createEpicMiddleware(rootEpic);
const createStoreWithMiddleware = applyMiddleware(epicMiddleware, logger)(createStore);
export default function configureStore(initialState) {
return createStoreWithMiddleware(rootReducer, initialState);
}
While the list component should be refreshed after EACH item is received, it is refreshed AFTER the whole list is received. Can someone point me to the blocking point in the code?
This isn't a solution to your particular issue (unless by accident lol) but I think a custom Observable is a better fit in this situation instead of a Subject. You can also hook into the Parser's error callback too.
Figured that others searching for streaming JSON with rxjs later might find this handy (untested)
function streamingJsonParse(data$) {
return new Observable((observer) => {
const parser = new Parser();
parser.onError = (err) => observer.error(err);
parser.onValue = (value) => {
if (!parser.key) {
observer.next(value);
}
};
// return the subscription so it's correctly
// unsubscribed for us
return data$
.subscribe({
next: (data) => parser.write(data),
error: (e) => observer.error(e),
complete: () => observer.complete()
});
});
}
function getJsonStream(url) {
return RxHR
.get(url)
.mergeMap(resp => streamingJsonParse(resp.body));
}
When you've had a chance to put together that jsbin let me know!
Turns out the problem was with the jsonParse lib. Switching to oboe.js
fixed it. Using the "!" node selector to select multiple root JSON elements i was able to transform the character stream to a user object stream.
Action
function getJsonStream(url) {
const emitter = new Subject();
const emitter = new Subject();
oboe(url)
.node('!', (item) => {
emitter.next(item);
})
.fail((error) => {
emitter.error(error);
});
return emitter;
}
export const fetchUsersEpic = action$ =>
action$.ofType(actionTypes.FETCH_USERS_REQUEST)
.switchMap(() => getJsonStream(`${api.API_BASE_URL}/user`))
.map(user => fetchUsersItemReceived(user));
I have a component which binds actions with it's props like this
I am not including the complete api call code in the handleButtonclick function here to avoid unnecessary code.
class LogInComponent extends Component {
static contextTypes = {
router: PropTypes.object.isRequired
}
handleLoginButtonClick() {
let token;
$.ajax(settings).done((response) => {
token = JSON.stringify(response.auth_token)
this.props.setAuthToken(token);
this.context.router.push('/app')
});
}
render(){
return (
<div className="LoginPage">
<button onClick={this.handleLoginButtonClick.bind(this)}>login</button>
</div>
);
}
}
const mapStateToProps = (state)=> ({
auth_token: state.Data.auth_token
})
function matchDispatchToProps(dispatch) {
return bindActionCreators({setAuthToken: actions.setAuthToken}, dispatch);
}
export default connect(mapStateToProps, matchDispatchToProps)(LogInComponent);
This is where my action and reducer are there:
import fetch from 'isomorphic-fetch'
const INITIAL_STATE = {
list: [],
selectedRows: [],
currentItem: {},
auth_token:null
}
const FETCH_LIST = 'FETCH_LIST'
const fetchList = ()=> (dispatch)=> {
dispatch({type: FETCH_LIST});
fetch('/api/items?n=50')
.then(resp => resp.json())
.then(data => dispatch(fetchListSuccess(data)))
.catch(err => dispatch(fetchListError(err)))
}
const FETCH_LIST_SUCCESS = 'FETCH_LIST_SUCCESS'
const fetchListSuccess = (list)=> {
console.log('Received List: ', list)
return {
type: FETCH_LIST_SUCCESS,
list
}
}
const FETCH_LIST_ERROR = 'FETCH_LIST_ERROR'
const fetchListError = (error)=> {
console.error(error)
return {
type: FETCH_LIST_ERROR,
error: error.message
}
}
const SELECT_ROWS = 'SELECT_ROWS'
const selectRows = (ids)=> {
return {
type: SELECT_ROWS,
ids
}
}
const SET_AUTH_TOKEN = 'SELECT_ROWS'
const setAuthToken = (token)=> {
return {
type: SET_AUTH_TOKEN,
payload: token
}
}
const SET_CURRENT_ITEM = 'SET_CURRENT_ITEM'
const setCurrentItem = (item)=> {
return {
type: SET_CURRENT_ITEM,
item
}
}
export const actions = {
fetchList,
selectRows,
setCurrentItem,
setAuthToken
}
export default function DataReducer(state = INITIAL_STATE, action){
switch(action.type){
case FETCH_LIST:
return {...state, isLoading: true }
case FETCH_LIST_SUCCESS:
return { ...state, isLoading: false, list: [...action.list] }
case FETCH_LIST_ERROR:
return {...state, isLoading: false, hasError: action.error }
case SELECT_ROWS:
return {...state, selectedRows: [...action.ids]}
case SET_CURRENT_ITEM:
return {...state, currentItem: {...action.item}}
case SET_AUTH_TOKEN:
return {...state, auth_token:action.payload}
default:
return state
}
}
I am getting an error like this
Where am I going wrong?