i have this code please check below there is this issue that store default state is not able to update using fetch api calling action and reducer as described below
configstore.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import products from './views/Products/reducer';
import categories from './views/Categories/reducer';
import user from './views/Login/reducer';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import createHistory from 'history/createBrowserHistory';
import { routerMiddleware } from 'react-router-redux';
console.log(user);
const defaultState = {
products: {
items: [],
isFetching: 0,
},
categories : {
items: [],
isFetching: 0,
},
user : {
email:'',
token:'',
isLoggedIn:false
}
};
const rootReducer = combineReducers({
products,
categories,
user
});
const store = createStore(
rootReducer,
defaultState,
composeWithDevTools(
applyMiddleware(thunk))
);
export default store;
reducer file contains the switch conditions based on different state keys
import
{ LOGGIN_USER } from './actions';
const isLoggedIn = (state = [], action) => {
switch (action.type) {
case LOGGIN_USER:
return Object.assign( {}, state, { user: action.payload.isLoggedIn } );
default:
return state;
}
};
const email = (state = [], action) => {
switch (action.type) {
case LOGGIN_USER:
return Object.assign( {}, state, { user: action.payload.email } );
default:
return state;
}
};
const token = (state = [], action) => {
switch (action.type) {
case LOGGIN_USER:
return Object.assign( {}, state, { user: action.payload.token } );
default:
return state;
}
};
export default combineReducers({
email,
token,
isLoggedIn
});
actions file
import 'whatwg-fetch';
import config from '../../config/config';
export const REQUEST_PRODUCTS = 'REQUEST_PRODUCTS';
export const RECEIVE_PRODUCTS = 'RECEIVE_PRODUCTS';
export const LOGGIN_USER = 'LOGGIN_USER';
// export const loggOnUser = products => ({
// type: LOGGIN_USER,
// products,
// });
export const authenticateUser = ( auser ) => ({
type: LOGGIN_USER,
auser
});
please anyone needed help on this why store state with key
user{
'email':''
'token':'',
'isLoggedIn':''
}
any help would be highly appreciated thanks in advance
Related
authReducer.js
import {
LOGIN_SUCCESS,
LOGIN_FAIL,
REGISTER_SUCCESS,
REGISTER_FAIL
} from '../Actions/types';
export default (state = { isLoading: true, user: [] }, action) => {
switch(action.type){
case LOGIN_SUCCESS:
localStorage.setItem('token',action.payload.token);
return {
...state,
user: action.payload.data,
}
case LOGIN_FAIL:
return state;
case REGISTER_SUCCESS:
return {
...state,
user: action.payload.data,
}
case REGISTER_FAIL:
return state;
default:
return state;
}
}
profile.js
import React from 'react'
import { useSelector} from 'react-redux'
export const EditProfile = () => {
const data = useSelector((state) => state.user);
return (
<div>
{data}
</div>
)
}
index.js (rootReducer)
import { combineReducers } from 'redux';
import authReducer from './authReducer';
export default combineReducers({
auth: authReducer,
})
store.js
import {createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './Reducers';
const initialState = {};
const middleware = [thunk];
const store = createStore(rootReducer,initialState,compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
));
export default store;
So Here when i logged in the details were on user object so i need to access then in profile.js so that i can display the details of the user
I don't how can i access i need to save the user data which are stored in user (redux store).
I don't know what i am missing any help will be grateful
I don't know how you setup your redux.
This is how I usually set them up:-
A. Reducer
/slices/auth.js
import { createSlice } from '#reduxjs/toolkit'
const initialState = {
user: [],
isLoading: false
}
export const authSlice = createSlice({
name: 'auth',
initialState,
// // The `reducers` field lets us define reducers and generate associated actions
reducers: {
setUser: (state, action) => {
// Redux Toolkit allows us to write "mutating" logic in reducers. It
// doesn't actually mutate the state because it uses the Immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes
state.user = action.payload
},
setLoading: (state, action) => {
state.loading = action.payload
}
}
})
export const { setUser, setLoading } = authSlice.actions;
// The function below is called a selector and allows us to select a value from
// the state. Selectors can also be defined inline where they're used instead of
// in the slice file. For example: `useSelector((state: RootState) => state.counter.value)`
export const selectUser = (state) => state.auth.user
export const selectLoading = (state) => state.auth.isLoading
export default authSlice.reducer;
B. Store
store.js
import { configureStore, getDefaultMiddleware } from '#reduxjs/toolkit'
import authReducer from '../slices/auth'
export const store = configureStore({
reducer: {
auth: authReducer
},
middleware: getDefaultMiddleware({
serializableCheck: false
})
})
C. App Component
import { Provider } from 'react-redux'
import { store } from '../app/store'
export default function App() {
return {
<>
<Provider store={store}>
{/* your content... */}
</Provider>
</>
}
}
D. Component (where you use the redux)
import { useContext } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { selectUser } from '../slices/auth'
export default function EditProfile() {
const dispatch = useDispatch()
const user = useSelector(selectUser)
return {
<>
{user}
</>
}
}
I am having this error in react-redux. I don't know how to solve it. I wanted to send a param which is taken from an api to another api and fetch results.
This is my store
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import rootReducer from "./Reducers/rootReducer";
const store = createStore(
rootReducer,
{},
compose(applyMiddleware(thunk), composeWithDevTools())
);
export default store;
This is my reducer code:
import * as types from "../Actions/types";
const initialState = {
posts: [],
table: [],
};
const postReducer = (state = initialState, action) => {
switch (action.type) {
case types.FETCH_DATA:
return {
...state,
posts: action.payload,
};
case types.FETCH_TABLE:
return {
...state,
table: action.payload,
};
default:
return {
...state,
};
}
};
export default postReducer;
This is my action code
export const getData = (from_userpart) => async (dispatch) => {
try {
const { data } = await api.getData(from_userpart);
dispatch({
type: types.FETCH_TABLE,
payload: data,
});
} catch (error) {
console.log(error);
}
};
When i use this code on the parent component,it works but i want to use that in my child component but it gives this error as i mentioned on the label. How to solve that?
useEffect(() => {
dispatch(getData(phone));
}, [dispatch]);
Change the setting of your store, your enhancer should come second.
let composeEnhancers = null
if (process.env.NODE_ENV === 'development') {
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
} else {
composeEnhancers = compose
}
const store = createStore(
rootReducer,
composeEnhancers(applyMiddleware(thunk))
);
I've noticed that i had imported my function from api folder not the action one. It works now
please help me with a situation around react-redux.
I have issues in updating the state ( which i try to do in a immutable way ), and the component where I use it, never rerenders.
/store/users/index.js
import { USER_LOGIN, USER_LOGOUT} from './actionTypes';
import {
USER_LOGIN,
USER_LOGOUT
} from './actionTypes';
const usersReducer = (user = {}, action) => {
switch(action) {
case USER_LOGIN : /* tried to change id manually, not based on payload, just to see if it works */
return {
...user,
name: 'New user',
isLoggedIn: true
}
case USER_LOGOUT:
return {
...user,
name: 'Anonymous',
isLoggedIn: false
}
default:
return user;
}
}
export default usersReducer;
/store/loops/index.js
import {
LOOPS_ADD
} from './actionTypes';
const loopsReducer = (loops =[], action) => {
switch(action) {
case LOOPS_ADD:
return [
...loops,
action.payload
]
default:
return loops;
}
}
export default loopsReducer;
/store/users/actions.js
import {
USER_LOGIN,
USER_LOGOUT
}
from './actionTypes';
export const userLogin = (newUser) => {
return {
type: USER_LOGIN,
}
}
export const userLogout = () => {
return {
type: USER_LOGOUT
}
}
/store/index.js
import {
createStore,
combineReducers,
applyMiddleware,
compose
} from 'redux';
/* import reducers */
import usersReducer from './users';
import loopsReducer from './loops';
/* import middleware */
import logger from 'redux-logger';
/* initial state */
const initialState = {
user: {
name: 'Anonymous',
isLoggedIn: false,
email: null,
lastLogin: null,
firstTimeLogin: false,
authProvider: 'email',
friendsCount: null
},
loops: []
}
/* reducers */
const rootReducer = combineReducers({
user: usersReducer,
loops: loopsReducer,
});
/* store creation */
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const middleware = composeEnhancers(applyMiddleware(logger));
const store = createStore(
rootReducer,
initialState,
middleware
);
export default store;
/pages/HomeScreen/HomeScreen.js
import React from 'react';
import {connect} from 'react-redux'
import {userLogin} from '../../store/users/actions';
class Home extends React.PureComponent {
render() {
return (
<React.Fragment>
<NavBar>Nav</NavBar>
<Listing>
<Filter>Filter</Filter>
<Card>
<CardAvatar>Avatar</CardAvatar>
<CardBody>Rest of the card</CardBody>
Salut {this.props.name}
<button onClick={() => this.props.login()}>login</button>
</Card>
</Listing>
</React.Fragment>
)
}
}
const mapStateToProps = (state) => {
return {
name: state.user.name
}
}
const mapDispatchToProps = (dispatch) => {
return {
login: () => dispatch(userLogin()),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Home);
I don't know if it matters but i'm using styled-components for styling.
I tried removing the combineReducers method, and remain with a single reducer, that did not help.
I tried removing the react-logger middleware, I tried using Immutable.jsbut even if the actions is triggered the redux state does not update, and the Home component doesn't rerender as well.
It seems you are not setting the user on your action:
export const userLogin = (newUser) => {
return {
type: USER_LOGIN,
}
}
Looks like it needs to be:
export const userLogin = (newUser) => {
return {
type: USER_LOGIN,
user: newUser
}
}
Without this there will be no change in state and also no render needed.
Of course, you would then need to change your reducer function so that it is dynamic:
case USER_LOGIN :
return {
...user,
name: action.user.name,
isLoggedIn: true
}
The answer was simple.
I was doing :
const loopsReducer = (loops =[], action) => {
switch(action) {
case LOOPS_ADD:
return [
...loops,
action.payload
]
default:
return loops;
}
}
instead i should have done
const loopsReducer = (loops =[], action) => {
switch(action.type) {
case LOOPS_ADD:
return [
...loops,
action.payload
]
default:
return loops;
}
}
Notice the switch(action) before to switch(action.type)
Sorry for wasting your time, and thank you for all your replies !
I'm trying to combine reduxForm with my custom reducers inside nextjs with no luck. I'm using this as initial working example: https://github.com/zeit/next.js/blob/master/examples/with-redux-wrapper/store.js
When I add reduxForm according to their docs, I get error: Cannot read property 'source' of undefined , which means that store doesn't even exist.
How my store.js looks now:
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
import { reducer as formReducer } from 'redux-form';
import thunkMiddleware from 'redux-thunk';
import axios from 'axios';
import getRootUrl from '../lib/api/getRootUrl';
const initialState = {
user: 0,
agent: 0,
};
export const actionTypes = {
FETCH_USER: 'FETCH_USER',
USER_AGENT: 'USER_AGENT',
};
// REDUCERS
const authReducer = (state = { user: 0 }, action) => {
switch (action.type) {
case 'FETCH_USER': return { user: action.payload };
default: return state;
}
};
const agentReducer = (state = { agent: 0 }, action) => {
switch (action.type) {
case 'USER_AGENT': return { agent: action.payload };
default: return state;
}
};
// ACTIONS
export const fetchUser = () => async (dispatch) => {
const ROOT_URL = getRootUrl();
const resUser = await axios.get(`${ROOT_URL}/api/current_user`);
dispatch({ type: actionTypes.FETCH_USER, payload: resUser.data });
};
export const getUserAgent = () => async (dispatch) => {
const ROOT_URL = getRootUrl();
const resAgent = await axios.get(`${ROOT_URL}/api/useragent`);
dispatch({ type: actionTypes.USER_AGENT, payload: resAgent.data });
};
const rootReducer = combineReducers({
authReducer,
agentReducer,
formReducer,
});
export const initStore = (newState = initialState) => createStore(
rootReducer,
newState,
compose(applyMiddleware(thunkMiddleware)),
);
Last working example. I tried to combine with-redux-wrapper syntax with reduxForm docs. reduxForm action and reducer don't work here: https://github.com/neone35/rearn/blob/master/server/store.js
How can I combine these two to use reduxForm inside my component containing Field components?
I solved my problem after reading more of this documentation:
https://redux.js.org/recipes/structuring-reducers/initializing-state
https://redux.js.org/recipes/structuring-reducers/using-combinereducers
Also, I've logged out console to see what props my component is receiving to resolve problem faster.
How my store.js looks now:
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
import { reducer as formReducer } from 'redux-form';
import thunkMiddleware from 'redux-thunk';
import axios from 'axios';
import getRootUrl from '../lib/api/getRootUrl';
const initialState = {
user: '0',
agent: '0',
};
export const actionTypes = {
FETCH_USER: 'FETCH_USER',
USER_AGENT: 'USER_AGENT',
};
// REDUCERS
const authReducer = (state = null, action) => {
switch (action.type) {
case actionTypes.FETCH_USER:
return action.payload || false;
default:
return state;
}
};
const agentReducer = (state = null, action) => {
switch (action.type) {
case actionTypes.USER_AGENT:
return action.payload || false;
default:
return state;
}
};
export const rootReducer = combineReducers({
user: authReducer,
agent: agentReducer,
form: formReducer,
});
// ACTIONS
export const fetchUser = () => async (dispatch) => {
const ROOT_URL = getRootUrl();
const resUser = await axios.get(`${ROOT_URL}/api/current_user`);
dispatch({ type: actionTypes.FETCH_USER, payload: resUser.data });
};
export const getUserAgent = () => async (dispatch) => {
const ROOT_URL = getRootUrl();
const resAgent = await axios.get(`${ROOT_URL}/api/useragent`);
dispatch({ type: actionTypes.USER_AGENT, payload: resAgent.data });
};
export const initStore = (newInitialState = initialState) =>
createStore(rootReducer, newInitialState, compose(applyMiddleware(thunkMiddleware)));
I separated all my reducers into functions which initialize state to null (because initStore gets passed zeros, and preloadedState (initialState) always has priority). I return raw value from action creator (without object) and it gets passed straight to combineReducers (which creates object) which is rootReducer inside createStore.
Fairly new to redux, and have gone through the official guides. Now I'm trying to do something solo. I have two reducers and am using react-thunk. When I dispatch an action after the first one it clears my collection of my other reducer. To illustrate what I mean is I have:
Actions.js
import axios from 'axios';
function fetchAtms() {
return axios.get('http://localhost:4567');
}
export const recievedAtms = (atms) => {
return {
type: 'RECIEVED_ATMS',
atms
}
}
export const completed = () => {
return {
type: 'COMPLETED',
}
}
export const loadMore = () => {
return {
type: 'LOAD_MORE',
}
}
export const loadAtms = (forPerson) => {
return function (dispatch) {
return fetchAtms().then((response) => {
let atms = response.data.map((item) => {return item['location']})
dispatch(recievedAtms(atms));
// When dispatch(completed()); is called
// it is clears my app collection.
dispatch(completed());
// $r.store.getState() => Object {app: {atms: []}, isLoading: false, router: Object}
}, (error) => {
console.log('implement me');
})
}
}
Reducers
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
const app = (state = {}, action) => {
switch (action.type) {
case 'RECIEVED_ATMS':
return {
atms: action.atms
}
default:
return {};
}
}
const isLoading = (state = true, action) => {
switch (action.type) {
case 'COMPLETED':
return !state;
default:
return state;
}
}
const appReducer = combineReducers({
app,
isLoading,
router: routerReducer
});
export default appReducer;
Store.js
import { createStore, applyMiddleware } from 'redux';
import { routerMiddleware} from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';
import thunk from 'redux-thunk';
import appReducer from './reducers/app';
export const history = createHistory()
const middleware = routerMiddleware(history);
const store = createStore(appReducer, applyMiddleware(middleware, thunk));
export default store;
If you hone in on Actions.js where in the loadAtms function I:
Fetch my atms
Dispatch receivedAtms
Dispatch Completed
When I dispatch completed() it clear my atms collection. I'm not entirely sure. I would not expect that since the states between the two reducers are separate. My expectation is:
After I've fired completed() I do not expect it to clear my collection of atms. The resulting state after calling completed() should look like this:
{
isLoading: false,
app: {atms: [{id: 1}, {id: 2}, {id: 3}]}
}
currently what is happening is this:
{isLoading: false, app: {}}
Any thoughts on what I may have done wrong here.
Your atms reducer is returning {} if the action isn't one it is looking for. Instead, you should be returning state I believe. So:
const app = (state = {}, action) => {
switch (action.type) {
case 'RECIEVED_ATMS':
return {
atms: action.atms
}
default:
return state;
}
}