I am new to react redux toolkit and redux-saga and have encountered an error where it only renders the last api call value from moviedb api. Also when I console log the state from useSelector, it renders multiple values. Here's my code
App.js
import "./App.css";
import Row from "./components/Row";
import requests from "./requests";
function App() {
return (
<div className="App">
<Row
title="Netflix Originals"
fetchUrl={requests.fetchNetflixOriginals}
/>
<Row title="Trending Now" fetchUrl={requests.fetchTrending} />
{/* <Row title="Top Rated" fetchUrl={requests.fetchTopRated} />
<Row title="Action Movies" fetchUrl={requests.fetchActionMovies} />
<Row title="Horror Movies" fetchUrl={requests.fetchHorrorMovies} /> */}
</div>
);
}
export default App;
Store.js
import { configureStore, combineReducers } from "#reduxjs/toolkit";
import createSagaMiddleware from "redux-saga";
import { watcherSaga } from "./sagas/rootSaga";
import movieReducer from "./ducks/movieSlice";
const sagaMiddleware = createSagaMiddleware();
const reducer = combineReducers({
movie: movieReducer,
});
const store = configureStore({
reducer,
middleware: [sagaMiddleware],
});
sagaMiddleware.run(watcherSaga);
export default store;
movieSlice.js
import { createSlice } from "#reduxjs/toolkit";
const movieSlice = createSlice({
name: "movie",
initialState: [],
reducers: {
getMovie() {},
setMovie(state, action) {
const movieData = action.payload;
return { ...state, ...movieData };
},
},
});
export const { getMovie, setMovie } = movieSlice.actions;
export default movieSlice.reducer;
rootSaga.js
import { takeEvery, takeLatest } from "redux-saga/effects";
import { getMovie } from "../ducks/movieSlice";
import { handleGetMovie } from "./handlers/movies";
export function* watcherSaga() {
yield takeEvery(getMovie.type, handleGetMovie);
}
handler
movie.js
import { call, put } from "redux-saga/effects";
import { requestGetMovie } from "../requests/movies";
import { setMovie } from "../../ducks/movieSlice";
export function* handleGetMovie(action) {
try {
const response = yield call(requestGetMovie, action.payload);
const { data } = response;
yield put(setMovie(data));
} catch (error) {
console.log(error);
}
}
requests
movie.js
import axios from "axios";
const baseURL = "https://api.themoviedb.org/3";
export function requestGetMovie(url) {
const URL = baseURL + url.fetchLink;
return axios.request({
method: "get",
url: URL,
});
}
requests.js
const APIKEY = "9cf4e09bc69e9849477a8ac79d29a205";
const requests = {
fetchTrending: `/trending/all/week?api_key=${APIKEY}&language=en=us`,
fetchNetflixOriginals: `/discover/tv?api_key=${APIKEY}&with_networks=213`,
fetchTopRated: `/movie/top_rated?api_key=${APIKEY}&language=en=us`,
fetchActionMovies: `/discover/movie?api_key=${APIKEY}&with_generes=28`,
fetchHorrorMovies: `/discover/movie?api_key=${APIKEY}&with_genres=27
`,
};
export default requests;
Row.js
import React, { useState, useEffect } from "react";
import styled from "styled-components";
import { useDispatch, useSelector } from "react-redux";
import { getMovie } from "../redux/ducks/movieSlice";
function Row({ title, fetchUrl }) {
const dispatch = useDispatch();
useEffect(() => {
dispatch(
getMovie({
fetchLink: fetchUrl,
})
);
}, [dispatch, fetchUrl]);
const movie = useSelector((state) => {
return state.movie.results;
});
console.log(movie);
return (
<RowContainer>
{title}
<CardsContainer>{movie && movie[0].name}</CardsContainer>
</RowContainer>
);
}
export default Row;
const RowContainer = styled.div`
color: white;
`;
const CardsContainer = styled.div`
color: white;
`;
Netflix orginals should display Lucifer while it renders Money Heist from the latest state value and also if i console.log the movie value, multiple values are repeated even if i have only two row component on app.js. If i have Row component on app.js 5 times, it displays the value 25 times on console.
image
image2
Your problem lies on the file movieSlice.js, exactly here:
setMovie(state, action) {
const movieData = action.payload;
return { ...state, ...movieData };
}
You are overriding the movie object everytime you call the setMovie action.
What you should do insted is to have separate actions for different movie types like this:
const movieSlice = createSlice({
name: "movie",
initialState: {
trendingMovies: [],
actionMovies: [],
},
reducers: {
setTrendingMovies(state, action) {
state.trendingMovies = action.payload;
},
setActionMovies(state, action) {
state.actionMovies = action.payload;
}
},
});
Related
I am using redux-toolkit to acquire accessToken from MSAL and redux-persist to persist the store in localStorage. I'm getting search results in clientlisting page. When I refresh the page it was working fine. But few minutes ago it throws me an error "Error in function eval in ./node_modules/redux-persist/es/persistReducer.js:144 baseReducer is not a function" I couldn't figure where am I doing wrong
store.js
import { configureStore } from '#reduxjs/toolkit'
import usersReducer from "./userSlice";
import storage from 'redux-persist/lib/storage';
import { persistReducer, persistStore } from 'redux-persist';
const persistConfig = { key: 'root', storage, }
const persistedReducer = persistReducer(persistConfig, usersReducer)
export const store = configureStore(
{
reducer: {
users: persistedReducer,
}
})
export const persistor = persistStore(store)
userSlice.js
import { useMsal } from "#azure/msal-react";
import { createAsyncThunk, createSlice } from "#reduxjs/toolkit";
import { loginRequest } from "./authConfig";
import { msalInstance } from "./pages/index";
export const fetchUsersToken = createAsyncThunk(
"users/fetchUsersToken",
async (dispatch, getState) => {
try {
const token = await msalInstance.acquireTokenSilent(dispatch)
.then((data) => data.accessToken)
return token
} catch (error) {
return error.response.data
}
}
);
const usersSlice = createSlice({
name: "users",
initialState: {
users: null,
loading: true
},
reducers: {},
extraReducers(builder) {
builder
.addCase(fetchUsersToken.pending, (state, action) => {
state.loading = true
})
.addCase(fetchUsersToken.fulfilled, (state, action) => {
state.loading = false,
state.users = action.payload
})
.addCase(fetchUsersToken.rejected, (state, action) => {
state.loading = false
});
}
})
export default usersSlice.reducer;
index.js
import React from "react"
import { Provider, useDispatch } from "react-redux";
import {persistor, store} from "../../store";
import Footer from "../Footer"
import { createTheme, ThemeProvider } from "#mui/material/styles"
import { PersistGate } from 'redux-persist/integration/react';
// Global styles and component-specific styles.
//For changing default blue color for mui text-fields
const theme = createTheme({
palette: {
primary: { main: "#000000" },
},
})
const Layout = ({ children }) => (
<div>
<ThemeProvider theme={theme}>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
{children}
<Footer/>
</PersistGate>
</Provider>
</ThemeProvider>
</div>
)
export default Layout
LandingPage.js ( where I'm dispatching the action.)
const request = {
...loginRequest,
account: accounts[0]
}
store.dispatch(fetchUsersToken(request))
Here is my index.js ( where msalInstance initiated )
import React from "react"
import { Helmet } from "react-helmet"
import { PublicClientApplication } from "#azure/msal-browser"
import { MsalProvider, useMsal } from "#azure/msal-react"
import { loginRequest, msalConfig } from "../authConfig"
import PageLayout from "../components/PageLayout"
import App from "./app"
import Layout from "../components/Layout"
//Redux
import { Provider, useDispatch } from "react-redux";
import {store} from "../store";
//Redux Ends here
export const msalInstance = new PublicClientApplication(msalConfig)
export default function Home() {
return (
<>
<Helmet>
<title>Client Engagement Lookup</title>
</Helmet>
<MsalProvider instance={msalInstance}>
{/* <Provider store={store}> */}
<Layout>
<PageLayout />
</Layout>
{/* </Provider> */}
</MsalProvider>
</>
)
}
After copy/pasting the code you shared into a running codesandbox I wasn't able to reproduce the error you describe, but I do see some discrepancies in the code, specifically in the userSlice.js file.
The main discrepancy I see is that the thunk is incorrectly accessing the thunkAPI. createAsyncThunk payload creators do take two arguments, the first is the arg (e.g. the request object) that is passed to the function and the second is the thunkAPI object. Update the thunk to correctly destructure dispatch and getState from the thunkAPI object.
export const fetchUsersToken = createAsyncThunk(
"users/fetchUsersToken",
async (request, { dispatch, getState }) => { // <-- destructure thunkAPI
try {
const { accessToken } = await msalInstance.acquireTokenSilent(request);
return accessToken;
} catch (error) {
return error.response.data;
}
}
);
A second discrepancy I noticed was in the fetchUsersToken.fulfilled reducer case where a Comma operator was used between the lines to set the loading and users states. This doesn't really effect much though since each operand mutates the state independently, but should still be fixed for readability's and maintenance's sake.
const usersSlice = createSlice({
name: "users",
initialState: {
users: null,
loading: true
},
extraReducers(builder) {
builder
.addCase(fetchUsersToken.pending, (state, action) => {
state.loading = true;
})
.addCase(fetchUsersToken.fulfilled, (state, action) => {
state.loading = false; // <-- own line, expression
state.users = action.payload; // <-- own line, expression
})
.addCase(fetchUsersToken.rejected, (state, action) => {
state.loading = false;
});
}
});
export default usersSlice.reducer;
Need some help.
As I am trying to get some understanding of React/REdux global state I made some simple get request.
This is done with Axios, thunk, Redux, but i can't get this working
I have Post.js file, nothing fancy
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import PostForm from './PostForm';
export class Post extends Component {
static propTypes = {
posts: PropTypes.any,
fetchPosts: PropTypes.func,
};
componentDidMount() {
const { fetchPosts } = this.props;
fetchPosts();
}
render() {
const { posts } = this.props;
return (
<div>
<PostForm addPost={this.onSubmit} />
<br />
<div>
{posts.map(post => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>
))}
</div>
</div>
);
}
}
export default Post;
Next i have my PostContainer.js
import { connect } from 'react-redux';
import Post from './Post';
import { fetchFromApi } from '../reducers/postReducers';
const mapStateToProps = state => ({
posts: state.posts,
});
const mapDispatchToProps = dispatch => ({
fetchPosts: () => dispatch(fetchFromApi()),
});
export default connect(mapStateToProps, mapDispatchToProps)(Post);
My reducer
import Axios from 'axios';
/* action type */
const FETCH_POSTS = 'FETCH_POSTS';
/* action creator */
export const fetchStarted = payload => ({ payload, type: FETCH_POSTS });
/* thunk */
export const fetchFromApi = () => {
return (dispatch, getState) => {
Axios.get('https://jsonplaceholder.typicode.com/posts?_limit=5').then(res =>
dispatch(fetchStarted(res.data))
);
};
};
/* reducer */
export default function reducer(state = [], action = {}) {
switch (action.type) {
case FETCH_POSTS: {
return {
...state,
data: action.payload,
};
}
default:
return state;
}
}
and my store
import { combineReducers, applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import postReducer from './reducers/postReducers';
const initialState = {
posts: {
data: {},
},
};
const reducers = {
posts: postReducer,
};
Object.keys(initialState).forEach(item => {
if (typeof reducers[item] == 'undefined') {
reducers[item] = (state = null) => state;
}
});
const combinedReducers = combineReducers(reducers);
const store = createStore(
combinedReducers,
initialState,
composeWithDevTools(applyMiddleware(thunk))
);
export default store;
All of that is doing not much. My map method is trying to map empty posts object. And for some reason my fetchPosts is not dispatched. I have reade some old posts here but still can't get this working
Thanks
Edit
this is my app.js file with container
import React from 'react';
import './App.css';
import Post from './components/PostContainer';
import { Provider } from 'react-redux';
import store from './store';
function App() {
return (
<Provider store={store}>
<div className='App'>
<Post />
</div>
</Provider>
);
}
export default App;
I managed to get this working.
Data was not there when my posts array was render. After passing simple if statemante all is working
I don't know how to load the data of the fetchLatestAnime action in the react app.js file.
My mission is to show the endpoint data that I am doing fetch.
I have already implemented the part of the reducers and action, which you can see in the part below. The only thing I need is to learn how to display the data.
App.js
import React from 'react';
import './App.css';
function App() {
return (
<div className="App">
</div>
);
}
export default App;
actions/types.js
export const FETCHING_ANIME_REQUEST = 'FETCHING_ANIME_REQUEST';
export const FETCHING_ANIME_SUCCESS = 'FETCHING_ANIME_SUCCESS';
export const FETCHING_ANIME_FAILURE = 'FETCHING_ANIME_FAILURE';
actions/animesActions.js
import{
FETCHING_ANIME_FAILURE,
FETCHING_ANIME_REQUEST,
FETCHING_ANIME_SUCCESS
} from './types';
import axios from 'axios';
export const fetchingAnimeRequest = () => ({
type: FETCHING_ANIME_REQUEST
});
export const fetchingAnimeSuccess = (json) => ({
type: FETCHING_ANIME_SUCCESS,
payload: json
});
export const fetchingAnimeFailure = (error) => ({
type: FETCHING_ANIME_FAILURE,
payload: error
});
export const fetchLatestAnime = () =>{
return async dispatch =>{
dispatch(fetchingAnimeRequest());
try{
let res = await axios.get('https://animeflv.chrismichael.now.sh/api/v1/latestAnimeAdded');
let json = await res.data;
dispatch(fetchingAnimeSuccess(json));
}catch(error){
dispatch(fetchingAnimeFailure(error));
}
};
};
reducers/latestAnimeReducers.js
import {
FETCHING_ANIME_FAILURE,
FETCHING_ANIME_REQUEST,
FETCHING_ANIME_SUCCESS
} from '../actions/types';
const initialState = {
isFetching: false,
errorMessage: '',
latestAnime: []
};
const latestAnimeReducer = (state = initialState , action) =>{
switch (action.type){
case FETCHING_ANIME_REQUEST:
return{
...state,
isFetching: true,
}
case FETCHING_ANIME_FAILURE:
return{
...state,
isFetching: false,
errorMessage: action.payload
}
case FETCHING_ANIME_SUCCESS:
return{
...state,
isFetching: false,
latestAnime: action.payload
}
default:
return state;
}
};
export default latestAnimeReducer;
reducers/index.js
import latestAnimeReducers from './latestAnimeReducers'
import {combineReducers} from 'redux';
const reducers = combineReducers({
latestAnimeReducers
});
export default reducers;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import resolvers from './redux/reducers/index';
import {createStore , applyMiddleware} from 'redux';
import {Provider} from 'react-redux';
import thunk from 'redux-thunk';
const REDUX_DEV_TOOLS = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(resolvers , REDUX_DEV_TOOLS)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
Ideally, this is how your app.js should look like. I created a working codesandbox for you here. Your initial latestAnime state was an empty array but the action payload you set to it is an object, so remember to pass payload.anime like i have done in the sandbox.
import React, { useEffect } from "react";
import { connect } from "react-redux";
import { fetchLatestAnime } from "./redux/actions/animesActions";
const App = props => {
const { fetchLatestAnime, isFetching, latestAnime, errorMessage } = props;
useEffect(() => {
fetchLatestAnime();
}, [fetchLatestAnime]);
console.log(props);
if (isFetching) {
return <p>Loading</p>;
}
if (!isFetching && latestAnime.length === 0) {
return <p>No animes to show</p>;
}
if (!isFetching && errorMessage.length > 0) {
return <p>{errorMessage}</p>;
}
return (
<div>
{latestAnime.map((anime, index) => {
return <p key={index}>{anime.title}</p>;
})}
</div>
);
};
const mapState = state => {
return {
isFetching: state.latestAnimeReducers.isFetching,
latestAnime: state.latestAnimeReducers.latestAnime,
errorMessage: state.latestAnimeReducers.errorMessage
};
};
const mapDispatch = dispatch => {
return {
fetchLatestAnime: () => dispatch(fetchLatestAnime())
};
};
export default connect(
mapState,
mapDispatch
)(App);
Sory for my English!
I am doing test work on React.js. The task is to make a regular blog. I ran into an unwanted problem. As a rule, componentDidMount makes entries, ready data and is called once.
I invoke the loadPosts action in the CDM to get the data.
The takeEvery effect sees the necessary saga, but does not cause it, but skips it.
When I press a button, everything works fine.
I'm new to React. All i tried is google
repository with project
branch - dev-fullapp
index.js
import store from "./redux/store";
const app = (
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>
);
store.js
import { createStore, compose, applyMiddleware } from "redux";
import createSagaMiddleware from "redux-saga";
import apiSaga from "./sagas/index";
import rootReducer from "./reducers/index";
const initialiseSagaMiddleware = createSagaMiddleware();
const storeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
storeEnhancers(applyMiddleware(initialiseSagaMiddleware))
);
initialiseSagaMiddleware.run(apiSaga);
export default store;
sagas.js
import { put, call, takeEvery } from "redux-saga/effects";
import { fetchGetPosts } from "../apis/index";
import { setErrorPosts, setPosts } from "../actions/actions-posts";
function* workerGetPosts() {
try {
const posts = yield call(fetchGetPosts);
yield put(setPosts(posts));
} catch (err) {
yield put(setErrorPosts(err));
}
}
export default function* watchSaga() {
yield takeEvery(POSTS.LOADING, workerGetPosts);
}
actions.js
import { POSTS } from "../constants";
export const loadPosts = () => {
console.log('action-load')
return {
type: POSTS.LOADING
}
};
export const setPosts = payload => ({
type: POSTS.LOAD_SUCCESS,
payload
});
export const setErrorPosts = error => ({
type: POSTS.ERROR,
error
});
rootReducer.js
import { combineReducers } from "redux";
import postsReducer from "./reducer-posts";
import loadReducer from "./reducer-load";
const rootReducer = combineReducers({
posts: postsReducer,
isLoad: loadReducer
});
export default rootReducer;
reducer-posts.js
import { POSTS } from "../constants";
const postState = {
posts: []
};
function postsReducer(state = postState, action) {
switch (action.type) {
case POSTS.LOAD_SUCCESS:
return {
...state,
posts: [...action.payload]
};
default:
return state;
}
}
export default postsReducer;
reducer-load.js
import { POSTS } from "../constants";
import { combineReducers } from "redux";
const loadReducerPosts = (state = false, action) => {
switch (action.type) {
case POSTS.LOADING: return false;
case POSTS.LOAD_SUCCESS: return true;
case POSTS.ERROR: return false;
default: return state;
}
};
const loadReducer = combineReducers({
isLoadPost: loadReducerPosts,
});
export default loadReducer;
news.jsx
class News extends Component {
componentDidMount() {
loadPosts();
}
render() {
CONST { loadPosts }this.props
return (
<main>
// code
<button onClick={loadPosts}>Test Button</button>
</main>
);
}
}
const mapStateToProps = (
{ posts: { loading, posts, success } }
) => ({
posts,
loading,
success
});
export default connect(
mapStateToProps,
{ loadPosts }
)(News);
loadPosts method is available as props to the React component in current case. Unlike in componentDidMount, on button click you are calling the function from props. You have to use this.props.loadPosts() on both places
I'm having problems putting all the pieces together so as to be able to display the data on my component. I can see the data display on the chrome console, and I don't get any errors on the page, but the data does not appear on my component.
If someone could help me see what I'm doing wrong and/or what I could do better
Below is a snippet with the code.
actionCreator
// #flow
// [TODO]: Add flow
import axios from 'axios';
const ROOT_URL = `https://toilets.freska.io/toilets`;
// const Actions = /* [TODO]: add flow */
export const FETCH_TOILETS = 'FETCH_TOILETS';
export const FETCH_TOILETS_PENDING = 'FETCH_TOILETS_PENDING';
export const FETCH_TOILETS_ERROR = 'FETCH_TOILETS_ERROR';
export function fetchToilets() {
const url = `${ROOT_URL}`;
const request = axios.get(url);
return dispatch => {
console.log(`IN ACTION fetchToilets`);
dispatch({ type: FETCH_TOILETS_PENDING })
axios.get(url)
.then(
response => dispatch({
type: FETCH_TOILETS,
payload: response
}),
error => dispatch({ type: FETCH_TOILETS_ERROR, payload: error })
);
};
};
reducer_cardList & rootReducer
// #flow
// [TODO]: Add flow
import { FETCH_TOILETS } from '../actions';
// type State = {} /* [TODO]: add #flow */
const initialState = [];
const CardListReducer = (state: State = initialState, action:Action ): State => {
switch(action.type) {
case FETCH_TOILETS:
return [ ...state, action.payload.data ];
default:
state;
}
return state;
}
export default CardListReducer;
// rootReducer
// #flow
// [TODO]: Add flow
import { combineReducers } from 'redux';
import CardListReducer from './reducer_cardList';
const rootReducer = combineReducers({
toilets: CardListReducer
});
export default rootReducer;
index.js
// #flow
// [TODO]: add #flow
import * as React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { createStore, applyMiddleware, compose } from 'redux';
import App from './App';
import rootReducer from './reducers';
import './index.css';
import registerServiceWorker from './registerServiceWorker';
const rootElement = document.getElementById('root');
const configueStore = createStore(
rootReducer,
applyMiddleware(thunk)
);
ReactDOM.render(
<Provider store={configueStore}>
<App />
</Provider>
,
rootElement
);
registerServiceWorker();
CardList.js
/* #flow */
// [TODO]: add flow
import * as React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchToilets } from '../../actions';
import CardItem from '../../components/CardItem/CardItem';
import './CardList.css';
type CardListProps = {
cards?: React.Node<any>
}
class CardList extends React.Component<CardListProps,{}> {
renderToilet() {
const toilets = this.props.toilets;
//const toilet = toilets.map(e => e.id)
console.log(`These are all the toilets: ${JSON.stringify(toilets)}`); // [[{"id":1,"map_id":"TOILET1","queue_time":1800,"queue_level":1,"type":"male","location":""}, ...etc
//console.log(`This is the toilet info: ${JSON.stringify(toilet)}`);
const id = toilets.map(toilet => toilet.id);
const mapId = toilets.map(toilet => toilet.map_id);
console.log(`This is the id: ${JSON.stringify(id)} and the mapId: ${JSON.stringify(mapId)}`); // This is the id: [null] and the mapId: [null]
// const queueTime = data.map(toilet => toilet.queue_time);
// const queueLevel = data.map(toilet => toilet.queue_level);
// const type = data.map(toilet => toilet.type);
// const location = data.map(toilet => toilet.location);
return (
<li key={id}>
<p>{mapId}</p>
{/*<p>{queueTime}</p>
<p>{queueLevel}</p>
<p>{type}</p>
<p>{location}</p> */}
</li>
)
}
componentDidMount() {
console.log(`fetchToilets() actionCreator: ${this.props.fetchToilets()}`);
this.props.fetchToilets();
}
render() {
return(
<section>
<ul className='card-list'>
{/* { this.props.toilet.map(this.renderToilet) } */}
{ this.renderToilet() }
</ul>
</section>
)
}
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({ fetchToilets }, dispatch);
}
const mapStateToProps = ({ toilets }) => {
return { toilets }
};
export default connect(mapStateToProps, mapDispatchToProps)(CardList);
You need to update your reducer like
const CardListReducer = (state: State = initialState, action:Action ): State => {
switch(action.type) {
case FETCH_TOILETS:
return [ ...state, ...action.payload.data ];
default:
state;
}
return state;
}
your old line
return [ ...state, action.payload.data ]
replace with
return [ ...state, ...action.payload.data ];
if you want to load on every time then you can just simple
return action.payload.data;
and Your render function
renderToilet() {
const toilets = this.props.toilets;
return arr.map((item, id) =><li key={id}>
<p>{item.id}</p>
{/*<p>{queueTime}</p>
<p>{queueLevel}</p>
<p>{type}</p>
<p>{location}</p> */}
</li>)
}