Redux inicial state has no effect - react-redux

I was trying to make a store but for some reason the initial state doesnt change when i alter the inicial state const:
this is the reducer with the inicial state:
import { GET_PRODUCT_BY_NAME, ADD_PRODUCT_TO_CART, CLEAR_CART, DELETE_ITEM, CURRENT_PRODUCT,INCREASE_AMOUNT } from '../../actionTypes'
const INITIALSTATE = {
currentProduct:{},
product: {},
list:[]
}
export function ProductReducer(state = INITIALSTATE, action) {
const { type, payload } = action
switch (type) {
case GET_PRODUCT_BY_NAME:
return {
...state,
user: payload.user,
}
case ADD_PRODUCT_TO_CART:
return {
...state,
list: [...state.list,payload]
}
case CLEAR_CART:
return {
list: []
}
case DELETE_ITEM:
console.log()
return {
list:[...state.list.slice(0, action.payload),
...state.list.slice(action.payload + 1)]
}
case CURRENT_PRODUCT:
return {
...state,
currentProduct: payload
}
case INCREASE_AMOUNT:
return {
...state,
}
default:
return state
}
}
this is the file with the store config details:
import { createStore, applyMiddleware } from 'redux'
import { persistStore, persistReducer } from 'redux-persist'
import ReduxThunk from 'redux-thunk'
import storage from 'redux-persist/lib/storage'
import rootReducer from './rootReducers'
const persistConfig = {
key: 'root',
storage,
}
const persistedReducer = persistReducer(persistConfig, rootReducer)
let store = createStore(persistedReducer, applyMiddleware(ReduxThunk))
let persistor = persistStore(store)
export { store, persistor }
and this is what i get when i console.log the state:
console.log
that result is from an older version

you encountered that issue because you had applied persistence before you settled on how your Product reducer initial state should look like. to solve this you need to either temporarily include your reducer into the persistConfig blacklist or setting the stateReconciler to autoMerge.

Related

using routerMiddleware function in react and redux

how can I use routerMiddleware to pass history to redux. I have tried below but not working. I couldn't find any resources that integrate the routerMiddleware. Here, I am trying to react-admin dashboard where it asks to pass history as props to redux store. so I am trying to use routeMiddleware to pass the history props.
import { createStore, combineReducers, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
import { routerMiddleware, connectRouter } from 'connected-react-router'
import { createBrowserHistory } from 'history'
import { postListReducer } from './reducers/postReducers'
const history = createBrowserHistory()
const reducer = combineReducers({
postList: postListReducer,
router: connectRouter(history),
})
const initialState = { postList: { posts: [] } }
const middleware = [thunk, routerMiddleware(history)]
const store = createStore(
reducer(history),
initialState,
composeWithDevTools(applyMiddleware(...middleware))
)
export default store
Reducers:
import {
POST_LIST_REQUEST,
POST_LIST_SUCCESS,
POST_LIST_FAIL,
POST_CREATE_REQUEST,
POST_CREATE_SUCCESS,
POST_CREATE_FAIL,
} from '../constants/postConstants'
export const postListReducer = (state = { posts: [] }, action) => {
switch (action.type) {
case POST_LIST_REQUEST:
return { loading: true }
case POST_LIST_SUCCESS:
return {
loading: false,
posts: action.payload,
}
case POST_LIST_FAIL:
return { loading: false, error: action.payload }
default:
return state
}
}

CRA Boilerplate Cannot read property 'initialLoad' of undefined In Redux -Saga & Reselect & redux-toolkit

Getting This Error When i use a useSelector hook to fetch data.
Im getting initial state undefined which cause the error.
selector.ts
import { createSelector } from '#reduxjs/toolkit';
import { RootState } from 'types';
import { initialState } from '.';
const selectSlice = (state: RootState) => state.initialLoad || initialState;
export const selectInitialLoad = createSelector([selectSlice], state => state);
index.ts
import { PayloadAction } from '#reduxjs/toolkit';
import { createSlice } from 'utils/#reduxjs/toolkit';
import { useInjectReducer, useInjectSaga } from 'utils/redux-injectors';
import { initialLoadSaga } from './saga';
import { InitialLoadState, RepoErrorType } from './types';
export const initialState: InitialLoadState = {
name: 'initial-load',
layouts: [],
loading: false,
error: null,
};
const slice = createSlice({
name: 'initialLoad',
initialState,
reducers: {
loadLayout(state) {
state.loading = true;
state.error = null;
state.layouts = [];
},
layoutLoaded(state, action: PayloadAction<[]>) {
const repos = action.payload;
state.layouts = repos;
state.loading = false;
},
layoutError(state, action: PayloadAction<string | RepoErrorType>) {
state.error = 'error';
state.loading = false;
},
},
});
export const { actions: appLayoutActions } = slice;
export const useAppLayoutSlice = () => {
useInjectReducer({ key: slice.name, reducer: slice.reducer });
useInjectSaga({ key: slice.name, saga: initialLoadSaga });
return { actions: slice.actions };
};
types.ts
/* --- STATE --- */
export interface InitialLoadState {
name: string;
loading: boolean;
error?: RepoErrorType | string | null;
layouts: [];
}
export enum RepoErrorType {
RESPONSE_ERROR = 1,
USER_NOT_FOUND = 2,
USERNAME_EMPTY = 3,
USER_HAS_NO_REPO = 4,
GITHUB_RATE_LIMIT = 5,
}
/*
If you want to use 'ContainerState' keyword everywhere in your feature folder,
instead of the 'InitialLoadState' keyword.
*/
export type ContainerState = InitialLoadState;
reducers.ts
/**
* Combine all reducers in this file and export the combined reducers.
*/
import { combineReducers } from '#reduxjs/toolkit';
import { InjectedReducersType } from 'utils/types/injector-typings';
/**
* Merges the main reducer with the router state and dynamically injected reducers
*/
export function createReducer(injectedReducers: InjectedReducersType = {}) {
// Initially we don't have any injectedReducers, so returning identity function to avoid the error
if (Object.keys(injectedReducers).length === 0) {
return state => state;
} else {
return combineReducers({
...injectedReducers,
});
}
}
this is my configuerStore.ts
/**
* Create the store with dynamic reducers
*/
import {
configureStore,
getDefaultMiddleware,
StoreEnhancer,
} from '#reduxjs/toolkit';
import { createInjectorsEnhancer } from 'redux-injectors';
import createSagaMiddleware from 'redux-saga';
import { createReducer } from './reducers';
export function configureAppStore() {
const reduxSagaMonitorOptions = {};
const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions);
const { run: runSaga } = sagaMiddleware;
// Create the store with saga middleware
const middlewares = [sagaMiddleware];
const enhancers = [
createInjectorsEnhancer({
createReducer,
runSaga,
}),
] as StoreEnhancer[];
const store = configureStore({
reducer: createReducer(),
middleware: [...getDefaultMiddleware(), ...middlewares],
devTools: process.env.NODE_ENV !== 'production',
enhancers,
});
return store;
}
work around
adding a condition to state
import { createSelector } from '#reduxjs/toolkit';
import { RootState } from 'types';
import { initialState } from '.';
const selectSlice = (state: RootState) => state && state.initialLoad || initialState;
export const selectInitialLoad = createSelector([selectSlice], state => state);
most of the files are of create react app boilerplate not change.
i tried the same on the cra boilerplate template without clean setup and it worked fine but after clean and setup it doesnt work how i need it too
Please define initialLoad into /src/types/RootState.ts
Example here

React action not triggering reducer

I defined setUser action in chatActions.js file below. From the console log, I can see the setUser action is fired. But corresponding reducer is never triggered.
export const SET_USER = "SET_USER";
export const CLEAR_USER = "CLEAR_USER";
export const setUser = user => {
console.log("In setUser"); <=== setUser action is fired for sure
return {
type: SET_USER,
payload: {
currentUser: user
}
};
};
export const clearUser = () => {
return {
type: CLEAR_USER
};
};
The reducer page is like below. From the console, I can see currentUser and isLoading being set to its initial state. But the state is never updated nevertheless the setUser action is fired.
import { createReducer } from '../../../app/common/util/reducerUtil'
import { SET_USER, CLEAR_USER, setUser, clearUser } from "../actions/chatActions"
const initialUserState = {
currentUser: null,
isLoading: "true"
};
export const chatUserReducer = (state = initialUserState, action) => {
switch (action.type) {
case SET_USER:
return {
currentUser: action.payload.currentUser,
isLoading: false
};
case CLEAR_USER:
return {
...state,
isLoading: false
};
default:
return state;
}
};
export default createReducer(initialUserState, {
[SET_USER]: setUser,
[CLEAR_USER]: clearUser
})
Here is the rootReducer page:
import { combineReducers } from 'redux';
import { reducer as FormReducer } from 'redux-form';
import chatUserReducer from '../../features/chat/reducers/chatUserReducer';
const rootReducer = combineReducers(
user: chatUserReducer
})
export default rootReducer;
The action is fired in the ChatDashboard component. user isn't null, and from above we can see setUser action is triggered, but somehow reducer isn't.
import { setUser, clearUser } from "../../chat/actions/chatActions";
const actions = {
setUser,
clearUser
}
const mapState = (state) => ({
currentUser: state.user.currentUser
})
class ChatComponent extends Component {
componentDidMount() {
firebase.auth().onAuthStateChanged(user => {
if (user) { <=== user is not null, this if condition is fulfilled
this.props.setUser(user);
}
});
}
...
}
export default withRouter(connect(mapState, actions)(ChatComponent));
You need to import chatUserReducer like:
import {chatUserReducer} from '../../features/chat/reducers/chatUserReducer';
RootReducer will be like this
import { combineReducers } from 'redux';
import { reducer as FormReducer } from 'redux-form';
import {chatUserReducer} from '../../features/chat/reducers/chatUserReducer';
const rootReducer = combineReducers(
user: chatUserReducer
})
export default rootReducer;

Load data before createStore

I’ve created some React files where one initializes a Redux store. However, I really need to load some data from a json file before store is initialized.
I’ve tried to import a script loading the json structure then assigning it to the createStore initialState value. But createStore runs before the data is loaded and assigned.
Is there any simple way to say “dont do anything before my axios call is done”???
Action types
actiontypes.js
export const LOAD_DATA_REQUEST='LOAD_DATA_REQUEST';
export const LOAD_DATA_SUCCESS='LOAD_DATA_SUCCESS';
export const LOAD_DATA_ERROR='LOAD_DATA_ERROR';
Actions
actions.js
import * as Actions from './actiontypes';
function load() {
return { type: Actions.LOAD_DATA_REQUEST };
}
function success(res) {
return { type: Actions.LOAD_DATA_SUCCESS, payload: res };
}
function error(ex) {
return { type: Actions.LOAD_DATA_ERROR, payload: ex };
}
export function loadData(url) {
return (dispatch) => {
dispatch(load());
axios.get(url).then((res) => {
dispatch(success(res));
}).catch((ex) => {
dispatch(error(ex));
});
};
}
use this in reducers that requires
import * as Actions from './actiontypes';
const newState = Object.assign({}, state);
switch (action.type) {
case Actions.LOAD_DATA_REQUEST:
{
//maybe you load
newState.loading = true;
return newState;
}
case Actions.LOAD_DATA_SUCCESS:
{
const res = action.payload;
//do what you need for this reducer
return newState;
}
case Actions.LOAD_DATA_ERROR:{
/// maybe you will want to show some error message in some reducer?
return newState;
}
}
You just need the first screen of your application on componentWillMount() call the loadData() action
I hope this can help you

how to pass action type redux in react navigation?

how to pass action type when login is succes in react navigation with redux ?
here my code...
import { Login } from '../constant/Constant'
import { NavigationActions } from "react-navigation";
import dispatch from "redux/es/createStore";
export function login(data) {
if (data.email === 'me') {
//NavigationActions.navigate({ routeName: 'Route' });
console.log("login success");
return (dispatch) => {
dispatch({type: 'Login'});
};
}else{
console.log("login error");
}
}
and this is my reducer.js, and how to pass action login to here, i try myself when login is success but cant passing action typelogin to here
import { combineReducers } from 'redux';
import { NavigationActions } from 'react-navigation';
import { AppNavigator } from '../navigators/AppNavigator';
import { reducer as formReducer } from 'redux-form'
const firstAction = AppNavigator.router.getActionForPathAndParams('Main');
const tempNavState = AppNavigator.router.getStateForAction(firstAction);
const secondAction = AppNavigator.router.getActionForPathAndParams('Login');
const initialNavState = AppNavigator.router.getStateForAction(
secondAction,
tempNavState
)
function nav(state = initialNavState, action) {
let nextState;
switch (action.type){
case 'Login':
nextState = AppNavigator.router.getStateForAction(
NavigationActions.back(),
state
);
break;
case 'Logout':
nextState = AppNavigator.router.getStateForAction(
NavigationActions.navigate({routeName: 'Login'}),
state
);
break;
default:
nextState = AppNavigator.router.getStateForAction(action, state);
break;
}
return nextState || state;
}
const initialAuthState = { isLoggedIn: false };
//How To pass login from action.js to here
function auth(state = initialAuthState, action) {
switch (action.type){
case 'Login':
console.log(action.type);
return { ...state, isLoggedIn:true };
case 'Logout':
return { ...state, isLoggedIn:false};
default:
return state;
}
}
const AppReducer = combineReducers({
nav,
auth,
form: formReducer
})
export default AppReducer;
can you paste redux/es/createStore, would like to see how dispatch method being exported
and what you can do is:
export function login(data) {
if (data.email === 'me') {
dispatch({type: 'Login'});
}else{
console.log("login error");
}
}
have a look at http://redux.js.org/docs/basics/Store.html, i don't see any store in your code
after you combine the reducer into store, you can do something like this
import { createStore } from 'redux'
let store = createStore(reducers); //connecting reducers to store
.
..
...
export dispatch = (action) => store.dispatch(action);

Resources