I am new with Redux and newer with Redux devtool.
I made a simple app in which you click on a user and it display some data about him.
So basically in the state I have the current selected user.
But I don't know why the state keep beeing empty in redux devtool. (not in the app)
Here is where I create my store :
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import App from './components/app';
import reducers from './reducers';
const createStoreWithMiddleware = applyMiddleware()(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<App />
</Provider>
, document.querySelector('.container'));
And here is the action :
export const USER_SELECTED = 'USER_SELECTED'
export function selectUser(user){
return {
type : USER_SELECTED,
payload : user
}
}
Here is a reducer :
import {USER_SELECTED} from '../actions/index'
export default function (state = null,action){
switch(action.type){
case USER_SELECTED :
return action.payload
}
return state
}
And finally a call to the action :
this.props.selectUser(user)
The app works very well but I am probably missing something.
Thanks for your help !
Try the following if you have setup the store using a middleware
import { createStore, applyMiddleware, compose } from 'redux';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, /* preloadedState, */ composeEnhancers(
applyMiddleware(...middleware)
));
Did you add this line to your store?
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
github.com/zalmoxisus/redux-devtools-extension#11-basic-store
I was looking at how I did it years ago and this would do the trick:
const store = createStore(reducers,
window.devToolsExtension && window.devToolsExtension()
)
For potential redux newcomers working on older projects/tutorials know that
window.devToolsExtensionis deprecated in favor ofwindow.REDUX_DEVTOOLS_EXTENSION`, and will be removed in next version of Redux DevTools: https://git.io/fpEJZ
as previously answered, replace with window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
I tried everything but still Redux was not showing in dev tools,
so I tried this chrome extension. Also reload after installing this extension.
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd/related?hl=en
It worked like a charm
Also the files,
store.js
import { createStore, applyMiddleware } from "redux"; // importing redux,redux-thunk(for my own use) and redux-devtools-extension
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
const initialState = {}; // declaring the variable with empty state
const composeEnhancers = composeWithDevTools({});
const store = createStore( // creating the store
finalReducer,
initialState,
composeEnhancers(applyMiddleware(thunk)) // you can leave this as it is if no middleware
);
App.js
import { Provider } from 'react-redux'; // importing the provider and store
import store from './store' // using store
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
I was facing the same issue.
I didn't get permanent solution yet but here is the workaround -
Change the chrome DevTools theme, only once it is required.
Now open devtools, you find the extension tab in DevTools.
You can again change the theme whatever you want to keep and this will fix your problem.
Related
so I'm doing a project where I'm using redux for the first time. I ended up having problem with states becoming undefined when I refresh the browser. To solve this I've tried implementing the redux-persist. But I get errors in my console which I don't know how I should solve. I only use redux for a single thunk-api call, therefor I got all my store code in my index.js file. I have seen all with threads where someone has a similar problem as me, but nothing solved it.
So here's my index.js file:
import React from 'react';
import {createRoot} from 'react-dom/client';
import App from './App';
import {configureStore} from '#reduxjs/toolkit'
import { Provider } from 'react-redux';
import blobReducer from './services/BlobRetriever'
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import { PersistGate } from 'redux-persist/es/integration/react'
const persistConfig = {
key:'persist-key',
storage,
}
const persistedReducer = persistReducer(persistConfig, blobReducer)
const store = configureStore({
reducer: {
blobs: persistedReducer,
},
middleware: getDefaultMiddleware =>
getDefaultMiddleware({
serializableCheck: false,
}),
})
const persistorStore = persistStore(store)
const rootElement = document.getElementById('root');
const root = createRoot(rootElement);
root.render(
<React.StrictMode>
<Provider store={store}>
<PersistGate loading={null} persistorStore={persistorStore}>
<App />
</PersistGate>
</Provider>
</React.StrictMode>,
);
and here's the error message I got: https://puu.sh/IX9Y2/e441359b38.png
am I doing something wrong?
I still don't have much experience with Redux.
But I have a situation at work where we will have an application with several modules.
Each module will have its own store.
I'm not able to merge all these stores into one store and then create a general store for all the project.
Could you tell me how can i do this?
import { combineReducers, createStore } from "redux";
const rootReducer1 = combineReducers({
reducerA: reducerA,
reducerB: reducerB,
reducerC: reducerC
});
export const store1 = createStore(rootReducer1);
/*****/
import { combineReducers, createStore } from "redux";
const rootReducer2 = combineReducers({
reducerD: reducerD,
reducerE: reducerE,
reducerF: reducerF
});
export const store2 = createStore(rootReducer2);
/*****/
import { combineReducers, createStore } from "redux";
import store1 from "../modules/module1/reducers";
import store2 from "../modules/module2/reducers";
const rootReducer = combineReducers({
store1: store1,
store2: store2
});
export const store = createStore(rootReducer);
/*****/
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import { Provider as ReduxProvider } from "react-redux";
import { store } from "./store";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(
<StrictMode>
<ReduxProvider store={store}>
<App />
</ReduxProvider>
</StrictMode>,
rootElement
);
I created a test project in codesandbox.io just to demonstrate the idea of what the project will be like.
combineReducers(reducers) helper function turns an object whose values are different reducing functions into a single reducing function. It can't combine multiple stores.
Besides, the best practice is Only One Redux Store Per App
A standard Redux application should only have a single Redux store instance, which will be used by the whole application
You can have each module act as a first-level slice on the redux state tree like this:
store.js:
// module 1
const rootReducer1 = combineReducers({
reducerA: reducerA,
reducerB: reducerB,
reducerC: reducerC
});
// module 2
const rootReducer2 = combineReducers({
reducerD: reducerD,
reducerE: reducerE,
reducerF: reducerF
});
// App
const rootReducer = combineReducers({
module1: rootReducer1,
module2: rootReducer2
});
export const store = createStore(rootReducer);
The structure of the redux state tree will be like this:
{
module1: {
reducerA: {},
reducerB: {},
reducerC: {}
},
module2: {
reducerD: {},
reducerE: {},
reducerF: {}
},
}
If the module becomes large in the future, you can split it into a separate application with its own redux store.
Im new to react, I'm trying to setup the login system with redux. In my Login component I'm using mapStateToProps with the connect method that react-redux offers.
When I tried to get what I needed from the store It kept saying that it was undefined. This is a snippet of my Login component:
function mapStateToProps(state) {
return {
loggingIn: state.authentication.loggedIn,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(userActions, dispatch),
alertActions: bindActionCreators(alertActions, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Login)
Here's how I tried to combine reducers:
import { combineReducers } from 'redux';
import authentication from './userReducer';
import alert from './alertReducer'
const rootReducer = () => combineReducers({
authentication,
alert
});
export default rootReducer;
However I couldn't access the logginIn props in the Login component. After trouble shooting for some frustrating hours I got it to work by removing the arrow function to this:
const rootReducer = combineReducers({
Can someone tell me why the arrow function didn't work? Thanks
Update: Here's how I imported the root reducer in the index.js file
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { Provider } from 'react-redux'
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk';
import rootReducer from './reducers'
const store = createStore(rootReducer, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'))
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
serviceWorker.unregister();
The docs tells you to call combineReducers to provide the root reducer.
The createStore method expects a reducer, not a function to call to get this reducer.
In addition to Vinicius' answer, you can refactor your combineReducers() call even more.
Instead of:
const rootReducer = () => combineReducers({
authentication,
alert
});
export default rootReducer;
which I have seen others do before, I guess personally the less code I need to write the cleaner, as long as it doesn't become esoteric looking, anyway just write it like this:
export default combineReducers({
authentication,
alert
});
You export and call the combineReducers() all in one go. Oh and to import it, since we removed rootReducer just do:
import reducers from "./reducers";
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducers,
composeEnhancers(applyMiddleware(reduxThunk))
);
I am using Redux thunk to dispatch multiple actions.
I have a store.js file
// store.js
import rootReducer from '../reducers/setInitData'; // reducer file
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
const middleware = applyMiddleware(thunk);
export default createStore(rootReducer, middleware, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
I have an app.js
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import CampaignCreate from './CampaignCreate' // component
import store from './store/store' // store.js
store.dispatch((dispatch) => {
dispatch({
type: 'SET_STATE',
payload : {
}
})
dispatch({
type : 'DISPLAY_REACT_COMPONENTS',
payload : {
dataLoadComplete : true
}
})
});
render(
<Provider store={store}>
<div id="campaign-init">
<CampaignCreate />
</div>
</Provider>,
document.getElementById('campaigns-react')
)
When I run my code I see the following error in my console:
Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
What is going wrong with the above code?
It's not the correct way to configure middlewares with redux devtools, according to redux devtools' readme, you should do this:
// don't forget import { compose } from 'redux'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(middleware));
I have my app (a boilterplate with few, my own features). It has a global store (build-in, came from the boilerplate), which looks like:
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'; //combine reducers from redux form
import { fromJS } from 'immutable';
import { routerMiddleware } from 'react-router-redux';
import createSagaMiddleware from 'redux-saga';
import createReducer from './reducers';
import { reducer as reduxFormReducer } from 'redux-form'; //registration form
const sagaMiddleware = createSagaMiddleware();
export default function configureStore(initialState = {}, history) {
// Create the store with two middlewares
// 1. sagaMiddleware: Makes redux-sagas work
// 2. routerMiddleware: Syncs the location/URL path to the state
const middlewares = [
sagaMiddleware,
routerMiddleware(history),
];
const enhancers = [
applyMiddleware(...middlewares),
];
// If Redux DevTools Extension is installed use it, otherwise use Redux compose
/* eslint-disable no-underscore-dangle */
const composeEnhancers =
process.env.NODE_ENV !== 'production' &&
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose;
/* eslint-enable */
const store = createStore(
createReducer(),
fromJS(initialState),
composeEnhancers(...enhancers)
);
// Extensions
store.runSaga = sagaMiddleware.run;
store.asyncReducers = {}; // Async reducer registry
// Make reducers hot reloadable, see http://mxs.is/googmo
/* istanbul ignore next */
if (module.hot) {
module.hot.accept('./reducers', () => {
import('./reducers').then((reducerModule) => {
const createReducers = reducerModule.default;
const nextReducers = createReducers(store.asyncReducers);
store.replaceReducer(nextReducers);
});
});
}
return store;
}
Few days ago I've implemented a redux-form (it works great), but unfortunately it has an own, local store, which is not compatibile with the global one and looks like:
import { createStore, combineReducers } from 'redux';
import { reducer as reduxFormReducer } from 'redux-form';
const reducer = combineReducers({
form: reduxFormReducer
});
const store = (window.devToolsExtension
? window.devToolsExtension()(createStore)
: createStore)(reducer);
export default store;
As far as I know, the store has to be global - the first one is, but the second one (for redux form) isn't.
I would like to ask you
How to mix these two stores into a single, common, global one?
Thank you for any answers!
Edit: Redux form comes from: https://codesandbox.io/s/qx95rm7gG
React redux comes from: https://github.com/react-boilerplate/react-boilerplate
Edit2: Files hierarchy:
-app
--index.js
--store.js (first one, global)
--containers
---UserRegistration
----index.js
----store.js (the second one, local)
but unfortunately it has an own, local store, which is not compatibile with the global one and looks like
This is not correct. The redux-form reducer is a standard reducer like any other and just needs to be combined into your reducer (from import createReducer from './reducers';).
If you are already combining reducers in createReducer (I assume you are because of the store.asyncReducers in the hot reloading), then you just need to include the reduxFormReducer with form as the key, something like:
import { combineReducers } from 'redux';
import { reducer as reduxFormReducer } from 'redux-form';
import someReducer from './someReducer';
import someOtherReducer from './someOtherReducer';
export default function createReducer(asyncReducers = {}) {
return combineReducers({
form: reduxFormReducer,
someReducer,
someOtherReducer,
...asyncReducers
});
}
If you share ./reducers/index.js I can make this answer more specific.