export multiple variable in one reducer file REDUX - reactjs

i want to ask how to export multiple const in 1 file reducers in redux
myreducers.js
import * as ActionTypes from '../actions/secone'
// PRODUCT TEMPLATE STATE
const productTemplate = (state={records:[], isFetching: false}, action) => {
switch (action.type) {
case ActionTypes.PRODUCT_TEMPLATE_REQUEST:
return { ...state, isFetching: true}
case ActionTypes.PRODUCT_TEMPLATE_SUCCESS:
return {
records: action.response,
isFetching: false,
}
default:
return state;
}
}
// PRODUCT ATTRIBUTE VALUES STATE
const productAttributeValues = (state={records:[], isFetching: false}, action) => {
switch (action.type) {
case ActionTypes.PRODUCT_ATTRIBUTE_VALUES_REQUEST:
return { ...state, isFetching: true}
case ActionTypes.PRODUCT_ATTRIBUTE_VALUES_SUCCESS:
return {
records: action.response,
isFetching: false,
}
default:
return state;
}
}
export default (productTemplate, productAttributeValues)
then how to import that reducers in main reducer that combine all the file,
what i did right now is to split ever const of my reducers in 1 file, and this is not efficient,
mainreducer.js
import { combineReducers } from 'redux'
import * as ActionTypes from '../actions/auth'
import authentication from './auth'
import productBrand from './secone'
import productTemplate from './product'
import resCity from './resCity'
import { routerReducer } from 'react-router-redux'
// Updates error message to notify about the failed fetches.
const errorMessage = (state = null, action) => {
const { type, error } = action
if (type === ActionTypes.RESET_ERROR_MESSAGE) {
return null
} else if (error) {
return action.error
}
return state
}
const rootReducer = combineReducers({
authentication,
errorMessage,
productTemplate,
// productAttributeValues,
productBrand,
resCity,
routing: routerReducer
})
export default rootReducer

I am not sure what you want to achive, but if your problem is to export more values from one file and import them to another file, the answer is not to use export default, but classic exports:
myreducers.js
export const productTemplate = (state={records:[], isFetching: false}, action) => { ... }
export const productAttributeValues = (state={records:[], isFetching: false}, action) => { ... }
and then import them
mainreducer.js
import { productTemplate, productAttributeValues } from "./myreducers" //fix the path
The difference between export and export default is very well described here: Typescript export vs. default export (does not matter the question is about TypeScript).

Related

How to persist only a subset of redux store into the local storage in redux-persist

I have a two reducers - userSignup and userLogin. I have to persist the store between page refreshes so i am using redux persist. However, i don't want to store the entire userSignup and userLogin states into localStorage, i only want to storea part of them.
UserSignupReducer.js
import {
USER_SIGNUP_SUCCESS,
USER_SIGNUP_FAILED,
USER_OTP_VERIFICATION_FAILED,
USER_OTP_VERIFICATION_SUCCESS,
SET_LOADING_TRUE,
SET_LOADING_FALSE,
} from './UserSignupTypes';
const initialState = {
loading: false,
userData: {},
signupErrors: {},
signupSuccess: false,
OTPSuccess: false,
OTPErrors: '',
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case SET_LOADING_TRUE:
return {
...state,
loading: true,
};
case SET_LOADING_FALSE:
return {
...state,
loading: false,
};
case USER_SIGNUP_SUCCESS:
return {
...state,
signupSuccess: true,
signupErrors: {},
userData: action.payload,
OTPErrors: '',
};
case USER_SIGNUP_FAILED:
return {
...state,
signupSuccess: false,
signupErrors: action.payload,
};
case USER_OTP_VERIFICATION_SUCCESS:
return {
...state,
OTPSuccess: true,
OTPErrors: '',
};
case USER_OTP_VERIFICATION_FAILED:
return {
...state,
OTPErrors: action.payload,
};
default:
return state;
}
};
export default reducer;
Here the state has many variables. But i don't want to persist errors, loading,.. into localStorage (as the UX would not be good if user sees the error even after refreshing the page). I only want to persist userData into the localStorage. Then i can use state reconciler = automergeLevel1 as stated in redux persist docs to get the new state after persist.
Similarly in userLoginReducer.js
import {
SET_LOADING_TRUE,
SET_LOADING_FALSE,
USER_LOGIN_SUCCESS,
USER_LOGIN_FAILED,
} from './UserLoginTypes';
const initialState = {
loading: false,
isloggedIn: false,
loginErrors: {},
username: '',
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case SET_LOADING_TRUE:
return {
...state,
loading: true,
};
case SET_LOADING_FALSE:
return {
...state,
loading: false,
};
case USER_LOGIN_SUCCESS:
return {
...state,
isLoggedIn: true,
username: action.payload,
loginErrors: {},
};
case USER_LOGIN_FAILED:
return {
...state,
isLoggedIn: false,
loginErrors: action.payload,
};
default:
return state;
}
};
export default reducer;
I only want to persist isLoggedIn into the localStorage.
rootReducer.js
import { combineReducers } from 'redux';
import userSignupReducer from './UserSignup/UserSignupReducer';
import userLoginReducer from './UserLogin/UserLoginReducer';
import { persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
const rootReducer = combineReducers({
userSignup: userSignupReducer,
userLogin: userLoginReducer,
});
const persistConfig = {
key: 'root',
storage,
whitelist: ['userSignup', 'userLogin'],
};
export default persistReducer(persistConfig, rootReducer);
store.js
import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import rootReducer from './rootReducer';
import { composeWithDevTools } from 'redux-devtools-extension';
import { persistStore } from 'redux-persist';
import thunk from 'redux-thunk';
export const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(logger, thunk)),
);
export const persistor = persistStore(store);
Please suggest any remedy for this problem. Thanks iin advance.
Use the filter transformator for redux-persist module redux-persist-transform-filter.
Installation:
npm install redux-persist-transform-filter
In your rootReducer.js:
...
import { createFilter } from "redux-persist-transform-filter";
...
const saveUserLoginSubsetFilter = createFilter("userLogin", ["isLoggedIn"]);
const persistConfig = {
key: 'root',
storage,
whitelist: ['userSignup', 'userLogin'],
transforms: [saveUserLoginSubsetFilter]
};
export default persistReducer(persistConfig, rootReducer);
The constant saveUserLoginSubsetFilter you are creating is taking two parameters, the first one is the name of the reducer you are referencing, the second one is the array of fields you want to persist. Indeed creating a subset of whitelisted entities to persist.
Then add the transforms array to the persistConfig and it should work.

Problem to load series data after fetch api using react/redux-thunk

Problem
Hello friends,
I'm developing an app with react + redux, the problem I have is that the series property that comes from
const mapStateToProps = (state) => {
   return {
     series: state.serieReducer
   }
}
It is showing me undefined in console, but if you see the image in the action it loads the 30 data in the array.
I would like if you could help me to solve the problem and be able to load the data in the render(){} function.
src/components/Home/index.js
import React, {Component} from 'react';
import Page from './page.js';
import fetchSeriesAction from '../../redux/actions/series/action.fetch.js';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux'
class Home extends Component {
componentDidMount() {
this.props.fetchSeries();
}
render(){
console.log('TESTING SERIES LIST:', this.props) // show undefined
return(
<Page/>
)
}
}
const mapStateToProps = (state) =>{
return{
series: state.serieReducer
}
}
const mapDispatchToProps = dispatch => bindActionCreators({
fetchSeries: fetchSeriesAction
}, dispatch)
export default connect(mapStateToProps , mapDispatchToProps)(Home);
src/redux/actions/series
serie/action.error.js
import {FETCH_SERIES_ERROR} from '../../types.js';
const fetchSeriesError = (error) =>{
return {
type: FETCH_SERIES_ERROR,
error: error
}
}
export default fetchSeriesError;
series/action.pending.js
import {FETCH_SERIES_PENDING} from '../../types.js';
const fetchSeriesPending = () =>{
return {
type: FETCH_SERIES_PENDING
}
}
export default fetchSeriesPending;
series/action.success.js
import {FETCH_SERIES_SUCCESS} from '../../types.js';
const fetchSeriesSuccess = (series) =>{
return {
type: FETCH_SERIES_SUCCESS,
series: series
}
}
export default fetchSeriesSuccess;
series/action.fetch.js
import fetchSeriesPending from './action.pending.js';
import fetchSeriesSuccess from './action.sucess.js';
import fetchSeriesError from './action.error.js';
const fetchData = () =>{
return async dispatch => {
dispatch(fetchSeriesPending());
await fetch('https://cinemanight.chrismichael.now.sh/api/v1/series/1')
.then(res => res.json())
.then(res => {
if(res.error) {
throw(res.error);
}
dispatch(fetchSeriesSuccess(res.series));
return res.series;
})
.catch(error => {
dispatch(fetchSeriesError(error));
})
}
}
export default fetchData;
reducers/series
series/result.js
import {
FETCH_SERIES_ERROR,
FETCH_SERIES_PENDING,
FETCH_SERIES_SUCCESS
} from '../../types.js';
const defaultState = {
pending: true,
series: [],
error: null
}
const reducer = (state = defaultState, action) =>{
switch(action.type){
case FETCH_SERIES_PENDING:
return{
... state,
pending: true
}
case FETCH_SERIES_SUCCESS:
return{
... state,
pending: false,
series: action.payload
}
case FETCH_SERIES_ERROR:
return{
... state,
pending: false,
error: action.error
}
default:
return state;
}
}
export default reducer;
series/index.js
import resultReducer from './result.js';
export default {
resultReducer
}
store.js
import {createStore , combineReducers , applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
import SeriesReducer from './reducers/series/index.js';
const middlewares = [thunk , logger];
const reducers = combineReducers({
... SeriesReducer
});
const store = createStore(reducers , applyMiddleware(... middlewares));
export default store;
You need to fix either action.success.js or your reducer because in reducer you are setting action.payload and you are sending series from your action.success.js
Either change your action.success.js to:
import {FETCH_SERIES_SUCCESS} from '../../types.js';
const fetchSeriesSuccess = (series) =>{
return {
type: FETCH_SERIES_SUCCESS,
payload: series
}
}
export default fetchSeriesSuccess;
or change your reducer like this:
import {
FETCH_SERIES_ERROR,
FETCH_SERIES_PENDING,
FETCH_SERIES_SUCCESS
} from '../../types.js';
const defaultState = {
pending: true,
series: [],
error: null
}
const reducer = (state = defaultState, action) =>{
switch(action.type){
case FETCH_SERIES_PENDING:
return{
... state,
pending: true
}
case FETCH_SERIES_SUCCESS:
return{
... state,
pending: false,
series: action.series
}
case FETCH_SERIES_ERROR:
return{
... state,
pending: false,
error: action.error
}
default:
return state;
}
}
export default reducer;
update your mapStateToProps method as well:
const mapStateToProps = (state) => {
return {
series: state.resultReducer
}
}

React Redux state not updating

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 !

react redux reducer unable to set fetch api data to store

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

"Expected the reducer to be a function." only on server

I am building an isomorphic app and I have a strange problem with my store and reducers. When I import my reducers in the client side store, it all works:
import reducers from '../Reducers';
...
let store = createStore(reducers, initial, composeEnhancers(applyMiddleware(...middleware)));
export default store;
But when I try to do the same on the server:
import reducers from '../source/js/Reducers';
I am getting error in the console
Error: Expected the reducer to be a function.
My reducers are like this:
import { INSERT_POST, INSERT_CONTENT, BUMP_PAGE, FETCH_COLLECTION } from '../Actions/Content';
const defaultState = {
currentPage: 0,
nextPage: 1,
content: [],
fetched: []
};
const reducer = (state = defaultState, action) => {
switch (action.type) {
case INSERT_POST:
return { ...state, content: [ ...state.content, action.payload ], fetched: [ ...state.fetched, action.url ] };
case INSERT_CONTENT:
const newState = {...state};
newState.content[action.payload.id].content = action.payload.data;
return newState;
case `${FETCH_COLLECTION}_SUCCESS`:
return { ...state, fetched: [ ...state.fetched, action.meta.previousAction.payload.request.url ]};
case BUMP_PAGE:
return { ...state, currentPage: state.nextPage, nextPage: ++state.nextPage };
default:
return state;
}
};
export default reducer;
...
import { START_TRANSITION, END_TRANSITION, TOGGLE_TRANSITION } from '../Actions/Transitions';
const defaultState = {
loaded: true
};
const reducer = (state = defaultState, action) => {
switch (action.type) {
case START_TRANSITION:
return { ...state, loaded: false };
case END_TRANSITION:
return { ...state, loaded: true };
case TOGGLE_TRANSITION:
return { ...state, loaded: !state.loaded };
default:
return state;
}
};
export default reducer;
And the main reducer:
import { combineReducers } from 'redux';
import Transitions from './Transitions'
import Content from './Content';
export default combineReducers({
Transitions,
Content
});
I have no idea of what to do with this. It's the first time I ever see such error. What can I do?

Resources