I am getting error, not during compilation, but in my browser,
I have attached the files here
message.js reducer file
import store from './index';
// ACTION TYPES
const FETCH_MESSAGES = "FETCH_MESSAGES";
// ACTIONS
export const fetchMessages = ( id ) => {
console.log(store.getState());
return {
type: FETCH_MESSAGES,
payload: id
}
}
// REDUCERS
export default function reducer( state = -1, action ) {
switch(action.type) {
case FETCH_MESSAGES :
return action.payload;
default:
return state;
}
}
index.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import chatReducer from './chat';
import messageReducer from './messages';
const reducer = combineReducers({
chatStore : chatReducer,
messageStore : messageReducer,
});
const store = createStore(reducer, applyMiddleware(thunk));
export default store;
Error Message
Scrrenshot of error message
Related
tree structure
i'm using create react app
src/reducers/index.js :
here is my reducer
const initialState = {
menuOpen:false,
};
function reducer (state = initialState, action = {}) {
switch (action.type) {
case 'MENU_CLICKED':
return {
...state,
menuOpen: !state.menuOpen,
};
default:
return state;
}
}
export default reducer;
default export
src/store/index.js :
here is my store
i used relative path for import my reducer
import { createStore, applyMiddleware, compose } from 'redux';
import reducer from 'src/reducers';
//const middlewares = applyMiddleware(lister les Middlewares);
//const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
//const enhancers = composeEnhancers(middlewares);
const store = createStore(reducer);
export default store;
Error :
ERROR in ./src/store/index.js 4:0-35
Module not found: Error: Can't resolve 'src/reducers' in 'C:\Users\apiot\Desktop\NoteToMyself\src\store'
Instead of
import reducer from 'src/reducers';
It should be
import reducer from '../reducers/index.js';
I am unable to access my state values saved in store on any screen. values reach to actions but when I access it from store it returns always undefined.
Every thing is in separate files
Reducer 1
import * as Actions from '../actionTypes'
import initialStore from './initialStore'
const homeModuleReducer = (state = initialStore, action) => {
switch (action.type) {
case Actions.SET_PROFILE_ONE:
console.log('call here')
return {
...state,
currentUser: action.profile
}
default:
return state;
}
}
export default homeModuleReducer
Reducer 2
import * as Actions from '../actionTypes'
import initialStore from './initialStore'
const loginModuleReducer = (state = initialStore, action) => {
switch (action.type) {
case Actions.SET_PROFILE:
return {
...state,
currentUser: action.profile
}
case Actions.SET_INITIAL_LOADING_STATUS:
return {
...state,
isInitialLoadingDone: action.loadingStatus
}
default:
return state;
}
}
export default loginModuleReducer
Combine Reducer
import { combineReducers } from 'redux'
import homeModuleReducer from './homeModuleReducer'
import loginModuleReducer from './loginModuleReducer'
export default combineReducers({
homeModuleReducer,
loginModuleReducer,
})
Store
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk';
import rootReducer from './reducers'
let store = createStore(rootReducer, applyMiddleware(thunkMiddleware));
export default store;
usage:
const mapStateToProps = (state) => ({
stateLoaded: state.rootReducer.isInitialLoadingDone,
profile: state.rootReducer.currentUser
});
Error:
undefined is not an object (evaluating 'state.rootReducer.isInitialLoadingDone')
You already combined your reducers so you can access reducer by it's key like this :
const mapStateToProps = (state) => ({
stateLoaded: state.homeModuleReducer.isInitialLoadingDone, // here homeModuleReducer is just an example. Change with reducer key in which isInitialLoadingDone is belong
profile: state.loginModuleReducer.currentUser
});
With hooks its much easier
wrap your root with store
import {Provider} from 'react-redux';
const App = () => {
return (
<Provider store={store}>
<Yourcomponent/>
</Provider>
);
};
export default App;
Access your state in any component like this
import { useSelector } from "react-redux";
const state = useSelector(state => state)
I have set up my redux store and everything seems alright all imports and exports seems correct to me but I do not seem to have a valid reducer and sagas. Been stuck, what am I doing wrong?
I get this error message
I have a store with the file structure below
Store
configStore.js
index.js
import { applyMiddleware, compose, createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from '../components/rootReducer';
export default function configureStore(initialState) {
const sagaMiddleware = createSagaMiddleware();
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
return {
...createStore(
rootReducer,
initialState,
composeEnhancers(applyMiddleware(sagaMiddleware)),
),
runSaga: sagaMiddleware.run,
};
}
import configureStore from './configStore';
import rootSaga from '../components/rootSaga';
const store = configureStore({});
store.runSaga(rootSaga);
export default store;
rootSaga
import { all } from 'redux-saga/effects';
import planets from './planets';
export default function* rootSaga() {
yield all([
planets.sagas(),
]);
}
rootReducer
import { combineReducers } from 'redux';
import planets from './planets';
export default combineReducers({
planets: planets.reducers,
});
In my components I have
reducers.js
import { UPDATE_PLANETS, LOAD_PLANETS } from './actionTypes';
const initialState = {
isPlanetsLoading: false,
planets: [],
};
export default (state = initialState, { type, payload }) => {
switch (type) {
case LOAD_PLANETS:
return {
...state,
isPlanetsLoading: true,
};
case UPDATE_PLANETS:
return {
...state,
isPlanetsLoading: false,
planets: payload,
};
default:
return state;
}
};
Planets.js
import { List } from "antd";
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { requestPlanets } from '../actions';
const Planets = () => {
const dispatch = useDispatch();
const { planets } = useSelector(
(state) => state.planets
);
console.log(planets);
useEffect(() => {
dispatch(requestPlanets());
}, [dispatch, planets]);
// return statement
};
export default Planets;
createStore returns the store. So don't spread it. Just associate the output of createStore to an object property say store.
in index.js, destructure the configStore object { store, runSaga }
configStore
export default function configureStore(initialState) {
const sagaMiddleware = createSagaMiddleware();
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
return {
store: createStore(
rootReducer,
initialState,
composeEnhancers(applyMiddleware(sagaMiddleware)),
),
runSaga: sagaMiddleware.run,
};
}
index.js
import configureStore from './configStore';
import rootSaga from '../components/rootSaga';
const { store, runSaga } = configureStore({});
runSaga(rootSaga);
export default store;
I am building a simple app to retrieve some recipes from an API URL.
I am reading the documentation of Thunk to implement it but I cannot understand how to set the async get request.
What is strange is that if I console.log the action passed into the reducer it definitely retrieves the correct object (a list of recipes for shredded chicken).
When I pass the action onto the the reducer, instead, it throws the error:
"Unhandled Rejection (Error): Given action "FETCH_RECIPES", reducer "recipes" returned undefined. To ignore an action, you must explicitly return the previous state. If you want this reducer to hold no value, you can return null instead of undefined."
Is there any error in my action creator? is the API call properly done?
Store
import React from 'react';
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux'
import SearchBar from './components/App';
import thunk from 'redux-thunk';
import 'bootstrap/dist/css/bootstrap.css';
import rootReducer from './reducers';
const store = createStore(rootReducer, applyMiddleware(thunk));
render(
<Provider store={store}>
<SearchBar />
</Provider>,
document.getElementById('root')
)
Component
import React, { Component } from 'react';
import { connect } from 'react-redux';
import './App.css';
import { Button } from 'reactstrap';
import { Form } from 'reactstrap';
import { bindActionCreators } from 'redux';
import {fetchRecipe } from '../actions';
class SearchBar extends Component {
constructor(props) {
super(props)
this.state = { term: ''};
this.typeRecipe = this.typeRecipe.bind(this)
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onFormSubmit(e) {
e.preventDefault()
this.props.fetchRecipe(this.state.term)
}
typeRecipe(e) {
this.setState({term: e.target.value});
}
render() {
return (
<div className="SearchBar">
<Form onSubmit={this.onFormSubmit}>
<input type='text'
value={this.state.term}
placeholder='ciao'
onChange={this.typeRecipe}
/>
<br/>
<Button id='ciao' className='btn-success'>Submit</Button>
</Form>
</div>
);
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchRecipe }, dispatch);
}
export default connect(null, mapDispatchToProps)(SearchBar);
Action creator
import axios from 'axios';
export const FETCH_RECIPES = 'FETCH_RECIPES';
const API_KEY = 'xxx';//not the real one.
export function fetchRecipe() {
const request = axios.get(`http://food2fork.com/api/search?key=${API_KEY}&q=shredded%20chicken`);
return (dispatch) => {
request.then(({data}) =>{
dispatch({ type: FETCH_RECIPES, payload: data})
})
}
}
reducer
import { FETCH_RECIPES } from '../actions';
export default function (state = {}, action) {
switch(action.type) {
case FETCH_RECIPES:
const newState = action.payload.data;
return newState;
default:
return state
}
}
combineReducer (index)
import recipeReducer from '../reducers/recipes_reducer';
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
recipes: recipeReducer
});
export default rootReducer;
Mistake is in the reducer return statement.
export default function (state = {}, action) {
switch(action.type) {
case FETCH_RECIPES:
const newState = {...state, data : action.payload.data};
return newState;
default:
return state
}
}
Here we are adding data key to the reducer state, to access this you can use do this in you container :
export default connect((state)=>{
var mapStateToProps = {};
if(state.recipes.data) {
mapStateToProps['recipes'] = state.recipes.data
}
return mapStateToProps;
}, mapDispatchToProps)(SearchBar);
and recipes data will be available as this.props.recipes.
My code is working fine, but I have an annoying problem whenever I make a coding mistake and get a runtime error. For instance, in one of my JSX pages I did Date() instead of new Date() and instead of reporting the actual error, I got...
Uncaught Error: Expected the reducer to be a function.
Any error I make almost always shows up as this. It's being reported from createStore.js, which is in my configureStore.jsx code below.
Is there a way that I can get better error reporting that helps me identify the real problem? Any help or ideas are greatly appreciated!!!
Here's my setup for reference....
main.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ReduxRouter } from 'redux-router';
import configureStore from './store/configureStore'
import routes from './routes';
const rootEl = document.getElementById('app-container');
const store = configureStore();
ReactDOM.render(
<div>
<Provider store={store}>
<ReduxRouter routes={routes} />
</Provider>
</div>
, rootEl
);
configureStore.jsx
import { createHashHistory } from 'history';
import { applyMiddleware, createStore, compose } from 'redux';
import { reduxReactRouter } from 'redux-router';
import thunk from 'redux-thunk';
import promiseMiddleware from 'redux-promise-middleware';
import rootReducer from '../reducers/rootReducer';
import routes from '../routes';
export default function configureStore(initialState = {}) {
const history = createHashHistory();
const middlewares = [
thunk,
promiseMiddleware({
promiseTypeSuffixes: ['PENDING','SUCCESS','ERROR']
})
];
const toolChain = [
applyMiddleware(...middlewares),
reduxReactRouter({
routes,
history
})
];
const store = compose(...toolChain)(createStore)(rootReducer, initialState);
if (module.hot) {
module.hot.accept('../reducers', () => {
const nextRootReducer = require('../reducers/rootReducer');
store.replaceReducer(nextRootReducer);
});
}
return store;
}
rootReducer.jsx
import { combineReducers } from 'redux';
import { routerStateReducer } from 'redux-router';
import siteReducer from './siteReducer';
const rootReducer = combineReducers({
router: routerStateReducer,
sites: siteReducer
});
export default rootReducer;
siteReducer.jsx
import {GET_SITES} from '../actions/siteActions';
const defaultState = {
isPending: null,
isSuccess: null,
isError: null,
error: null,
data: null
};
export default function siteReducer(state = defaultState, action) {
switch (action.type) {
case `${GET_SITES}_PENDING`:
return {
...defaultState,
isPending: true
};
case `${GET_SITES}_SUCCESS`:
return {
...defaultState,
isSuccess: true,
error: false,
data: action.payload
};
case `${GET_SITES}_ERROR`:
return {
...defaultState,
isError: true,
error: action.payload
};
default:
return state;
}
}
Change the following line:
const nextRootReducer = require('../reducers/rootReducer');
To:
const nextRootReducer = require('../reducers/rootReducer').default;
Use export const variable_name instead of const variable_name whenever you want to export that variable.
For ex: rootReducer.jsx should be re-written as
import { combineReducers } from 'redux';
import { routerStateReducer } from 'redux-router';
import siteReducer from './siteReducer';
export const rootReducer = combineReducers({
router: routerStateReducer,
sites: siteReducer
});
export default rootReducer;
Note the extra export specifier with const rootReducer
My issue was importing Store from the root reducer path rather than the actual bundled store root (with devtools on the window and root reducer, middleware being composed, etc).
import Store from '../../../src/state/Store/reducer';
changed to
import Store from '../../../src/state/Store';