Configuration store variation with React/redux and thunkMiddleware - reactjs

I've been through many examples to understand how Redux-Thunk works and most the time the store is configured in a various way. I guess there's the old way or the new way but I'm kind of lost. Here is three pattern that I've identified. If someone can explain me the differences between them :
The simple way :
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'
const loggerMiddleware = createLogger()
const store = createStore(rootReducer, applyMiddleware( thunkMiddleware, loggerMiddleware));
the Official Reddit Async Exemple way (here) :
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'
const loggerMiddleware = createLogger()
export default function configureStore(preloadedState) {
return createStore(
rootReducer,
preloadedState,
applyMiddleware(
thunkMiddleware,
loggerMiddleware
)
)
}
the old way ?
import {compose, createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
const createAppStore = compose(
applyMiddleware(thunkMiddleware)
)(createStore);
export default function configureStore(initialState){
const store = createAppStore(rootReducer, initialState);
return store;
};
From there I have at least four questions :
Do we still need to use compose ? I only find it in "old" exemple ?
Is there any differences between import ReduxThunk from
'redux-thunk' and import thunkMiddleware from 'redux-thunk' ?
Does the simple way is also correct ?
I don't understand the preloadedState pattern from the Reddit Async Exemple.
thanks.

The signature for createStore is createStore(reducer, [preloadedState], [enhancer]).
preloadedState is an initial state you load before you initialize your app. For instance, if you prerender your first page on a server and want to pass app state as a JSON inside your HTML. Sometimes you need to fetch this state asynchronously that is where the second example is useful. You fetch your state and create a store using that state in the callback of your ajax call.
The third argument.
enhancer is a higher-order function that composes a store creator to return a new, enhanced store creator. applyMiddleware is a store enhancer shipped with redux. If you want to combine multiple store enhancers you need to use compose function.
For instance, redux-devtools-extension for chrome is an enhancer so to use it in your app you would need compose function
let store = createStore(reducer, initialState, compose(
applyMiddleware(...middleware),
window.devToolsExtension ? window.devToolsExtension() : f => f
));
When you import something from 'redux-thunk' you use default export so you can name your variable as you want. It doesn't matter.
A simple way is also correct if you don't need anything fancy it would work just fine.

Related

what is the difference between Redux CombineReducers and Redux-toolkit ConfigureStore

import { configureStore } from "#reduxjs/toolkit";
import testSlice from "./testSlice";
import {combineReducers} from "redux";
const rootReducer = combineReducers({test: testSlice})
export const store = configureStore({
reducer: rootReducer,
});
Which one is better? for performance and use purpose. Which is good to use?
They are totally different things.
The reducer option is an object of slice reducers, like {users : usersReducer, posts : postsReducer}, configureStore will automatically create the root reducer by passing this object to the Redux combineReducers utility. See here
RTK configureStore setup the redux store configuration, not only reducer, but also middlewares, dev tools, preloaded state, and enhancers.
The Redux combineReducers helper function turns an object whose values are different reducing functions into a single reducing function

How would I add stack tracing to my current Redux Devtools setup?

Here is my current redux store assignment:
import { composeWithDevTools } from 'redux-devtools-extension';
import { createStore, applyMiddleware } from 'redux';
import { PersistGate } from 'redux-persist/integration/react';
import reduxThunk from 'redux-thunk';
const persistedReducer = persistReducer(persistConfig, reducers);
const store = createStore(
persistedReducer,
composeWithDevTools(applyMiddleware(reduxThunk)),
);
I'd like to be able to stack trace within my project using Redux Devtools. The examples given don't really match my setup and was just wondering how I would go about in adding something like the trace property without totally rewriting my variable assignment to match theirs.
Have you tried setting options to composeWithDevTools and then dropping that into createStore?
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
const composeEnhancers = composeWithDevTools({trace: true}); // <<< set options here
const store = createStore(
reducer, /* preloadedState, */
composeEnhancers( // <<< use it here
applyMiddleware(...middleware),
)
);

It looks like you are passing several store enhancers to createStore() react-thunk

I was experimenting with redux for a bit and came across a problem, I found the solution( here: React Redux - Error passing several store enhancers to createStore()) however this is not the solution I wanted. Basically I have the same problem as the person asking the question basically when creating the redux store we did this:
import { createStore, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import reduxThunk from 'redux-thunk';
import rootReducer from "./reducers";
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(reduxThunk)),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
But the code above is not the correct way of creating the store, apparently you should create the store is like this:
import { createStore, compose, applyMiddleware } from "redux";
import reduxThunk from "redux-thunk";
import rootReducer from "./reducers";
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
composeEnhancer(applyMiddleware(reduxThunk))
);
However in the solution above I am not using the composeWithDevTools module which is what I wanted to use. Is there a way to use composeWithDevTools in this case and is it necessary to use composeWithDevTools?
Today you should be using our official Redux Toolkit package to write your Redux logic, and in particular, RTK's configureStore API.
configureStore automatically sets up the Redux DevTools Extension for you, automatically turns on the thunk middleware, and also makes it very easy to add additional store enhancers if desired.
The example you're showing would simply be:
const store = configureStore({
reducer: rootReducer
});
and the behavior is exactly the same as what you showed.

redux store Error while creating store after installing redux-saga

I want to use redux-saga in my project and after installing redux-saga when I make changes in store.js file it gives error
Error: It looks like you are passing several store enhancers to createStore(). This is not supported. Instead, compose them together to a single function.
# store.js
import { createStore, applyMiddleware, compose } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import rootReducer from './reducers'
import createSagaMiddleware from 'redux-saga';
import rootSaga from './actions/sagas';
const sagaMiddleware = createSagaMiddleware();
const composeEnhancers =
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
}) : compose;
const enhancer = composeEnhancers(
applyMiddleware(sagaMiddleware)
);
const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
enhancer,
composeWithDevTools(applyMiddleware(...middleware))
);
sagaMiddleware.run(rootSaga);
export default store;
I don't know much about stores. please see if you can help.
You are composing your devtools and middlewares twice there use only one of the two.
const store = createStore(
rootReducer,
initialState,
// either this line
enhancer,
// or this line
composeWithDevTools(applyMiddleware(...middleware))
);
Also, just FYI: this is a quite outdated style of redux. If you are learning redux right now and follow this approach, you will write a LOT of unneccessary boilerplate. Please follow the official redux tutorials over at the official redux documentation instead of whatever tutorials you are learning from right now.

Connecting Redux devtools and Thunk middleware to store

I am trying to connect redux-devtools to my store but I keep getting the following error:
" It looks like you are passing several store enhancers to createStore(). This is not supported. Instead, compose them together to a single function error."
*Using Thunk as middleware.
tried to use an enhancer but I was still getting different errors.
Help will be appreciated.
this is how my store looks like:
import {createStore,applyMiddleware} from 'redux';
import thunk from 'redux-thunk'
const initialState={
bla:"",
bla:"",
bla:"",
}
const reducer = (state= initialState, action)=>{
bla bla bla..
actions...
}
const store= createStore(reducer,applyMiddleware(thunk))
export default store;
From the doc:
import { createStore, applyMiddleware, compose } from 'redux';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(...middleware));
));
The simplest way is to install
npm install --save-dev redux-devtools-extension
then :
import { createStore, applyMiddleware } from 'redux';
import thunk from "redux-thunk";
import { composeWithDevTools } from 'redux-devtools-extension';
const middlewares = [thunk, ...others ];
const appReducers = combineReducers({
yourReducers
});
const store = createStore(appReducers, composeWithDevTools(
applyMiddleware(...middleware),
// other store enhancers if any
));
read more about the configuration
This worked for me. I just used the compose method to combine Thunk and Dev Tools.
import { createStore, applyMiddleware , compose} from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers'
const store = createStore(rootReducer, compose(applyMiddleware(thunk), window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()));
export default store
Reason for not working : When we use redux-devtools-extension and redux-thunker together, it not working because of incorrect configuration. I was experiencing the same problem.
Solution :
npm Packages Required :
npm i redux
npm i redux-devtools-extension
npm i redux-thunker
Code:
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import createThunkerMiddleware from 'redux-thunker';
import rootReducer from './reducers/index';
const initialState = {};
const thunk = createThunkerMiddleware({
extraArgumentsEnhanced: {
fetch,
},
});
const middleware = [thunk];
export default createStore(
rootReducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
I have already answered this in a similar question, here is the link.
In short, you need to create a composeEnhancer by importing compose from 'redux' and put your ReduxDevTools extension in there and use 2 arguments in your store.
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const Store = createStore(rootReducer, composeEnhancer(applyMiddleware(thunk)))
ReactDOM.render(<Provider store={Store}><BrowserRouter><App/></BrowserRouter></Provider>, document.getElementById('root'));

Resources