Redux - Providing reducer function for create store error - redux

In this document, it wants 3 arguments, the 1st being the reducer.
https://redux.js.org/api/createstore
I understand that there needs to be a function defined, but where would this be coming from? Am I defining it or is this something that is imported?
Right now, I'm getting an error that rootReducer is not defined.
I guess I'm not sure what to do as for this particular assignment, all I needed to do was return JSON data from a provided endpoint.
I've done without the use of Redux/Thunk, but the requirements ask for it, along with Jest.
What would I add to the first argument?
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
const initialState = {};
const middleware = [thunk];
const store = createStore(rootReducer, initialState, compose(
applyMiddleware(...middleware),
window._REDUX_DEVTOOLS_EXTENSION_ ?
window.__REDUX_DEVTOOLS_EXTENSION__() : f => f
));

Please take the time to read through the Redux documentation. Redux expects you to write "reducer functions" that define how the state is initialized and updated.
Specific to the question of store setup, see the docs page on "Configuring Your Store".

Related

Handling namespaced modular approach on PINIA, Vue3+Typescript

normally I was using namespaced vuex. But I am deciding to quit vuex because Pinia has the vue core team support. I think it's better for the future developements. Now I am creating store with a modular approach but couldn't really understand how to handle that part on typescript project.
let's say I have a user interface.
interface User {
email: string,
username: string,
}
export default User;
and in store/modules/state.ts I am calling the Type and creating a user state.
import User from "../../types/User"
export const state = () => {
return {
user: {} as User | null,
};
}
and in store/modules/index.ts I should import the state. And make the namespace: true then export it for the defineStore() for pinia store.
import {state} from "./state"
export default {
namespace: true,
state,
}
in store/index.ts
import {defineStore} from "pinia"
import {data} from "./modules"
export const Store = defineStore(data)
okay above, namespace part I use the vuex way. But what is the right approach for the pinia. Additionally, getters and actions as well. How should export and use them.
According to official Pinia docs:
Vuex has the concept of a single store with multiple modules. These modules can optionally be namespaced and even nested within each other. The easiest way to transition that concept to be used with Pinia is that each module you used previously is now a store.
So now you should think about each vuex module as an separated pinia store. Looking at your example it could look like this. create file in store/modules/index.ts and paste:
import { defineStore } from "pinia";
import state from "store/modules/state.ts"; // Assuming that it's path to user state
export const useUserStore = defineStore('some/vuex/module/name', {
state: state,
getters: {
// your getters here, check the Offical Pinia above
},
actions: {
// your actions and mutations here, also check the offical Pinia Docs
}
})
If you want to split getters, actions and state into multiple files, there is discussion on offical repo issue where I provided example, that is working for me. Here is a link

Redux Persist + Redux toolkit $CombinedState error

I'm trying to add redux persist to redux toolkit but for some reason I get an Exported variable 'store' has or is using name '$CombinedState' from external module ".../node_modules/redux/index" but cannot be named. error on vscode.
This is my store configuration file with the added persist config, which if I remove, works fine.
import { configureStore } from "#reduxjs/toolkit";
import { persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import { createEpicMiddleware } from "redux-observable";
import rootEpic from "onsite/redux/rootEpic";
import rootReducer from "onsite/redux/rootReducer";
const epicMiddleware = createEpicMiddleware();
const persistConfig = {
key: "root",
storage: storage,
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
// Line that shows error
const store = configureStore({
reducer: persistedReducer,
middleware: [epicMiddleware],
});
export default store;
epicMiddleware.run(rootEpic);
Other things I have tried are putting the combineReducers declaration (from rootReducerimport) into the same file or converting the file into plain javascript, with same or similar results. For some reason typescript decides to still haunt me on a javascript file :)
The code still runs, so I'm tempted to leave it like that, but I would like to get rid of it.
I had the same issue, and here's what I figured out:
You need to include Store from redux, and use it as your type definition for your own store return value. Short answer:
import { Store } from 'redux';
[...]
const store:Store = configureStore([...])
[...]
export default store;
Longer answer:
As I understand it, what was happening is that Store type uses $CombinedState as part of its definition. When configureStore() returns, it inherits the State type. However since State is not explicitly used in your code, that now means that your code includes a value that references $CombinedState, despite it not existing anywhere in your code either. When you then try to export it out of your module, you're exporting a value with a type that doesn't exist within your module, and so you get an error.
You can import State from redux (which will in turn explicity cause your code to bring in $CombinedState), then use it to explicitly define store that gets assigned the return of configureStore(). You should then no longer be exporting unknown named types.
You can also be more specific with your Store type, as it is a generic:
const store:Store<RootState>
Although I'm not entirely sure if that would be a circular dependency, since your RootState depends on store.
Adding a
import { $CombinedState } from '#reduxjs/toolkit'
in that file should usually resolve that error.

Why Not "pre-connect" Redux Action Creators?

In a typical React/Redux codebase you have action creator functions like:
Actions.js:
export const addFoo = foo => ({ foo, type: 'ADD_FOO' });
Then you use connect to create a version of that function which dispatches the action, and make it available to a component:
Component.js:
import { addFoo } from 'Actions';
const mapPropsToDispatch = { addFoo };
const SomeComponent = connect(mapStateToProps, mapPropsToDispatch)(
({ addFoo }) =>
<button onClick={() => addFoo(5)}>Add Five</button>;
)
I was thinking, rather than mapping each action creator to its dispatched version inside the connect of every component that uses them, wouldn't it be simpler and cleaner if you could just "pre-connect" all of your action creators ahead of time:
Store.js:
import { createStore } from 'redux'
const store = createStore(reducer, initialState);
export const preConnect = func => (...args) => store.dispatch(func(...args));
Actions.js (2.0):
import { preConnect } from 'Store';
export const addFoo = preConnect(foo => ({ foo, type: 'ADD_FOO' }));
Component.js (2.0):
import { addFoo } from 'Actions';
const SomeComponent = () =>
<button onClick={() => addFoo(5)}>A Button</button>;
Am I missing any obvious reason why doing this would be a bad idea?
You make a reference to the dispatch() function in your code here:
export const preConnect = func => (...args) => store.dispatch(func(...args));
But in the world of React-Redux there is no direct reference to the dispatch() function inside of our components. So what's going on?
When we pass our action creator into the connect() function, the connect() function does a special operation on the functions inside the actions object.
export default connect(mapStateToProps, { selectSong })(SongList);
The connect() function essentially wraps the action into a new JavaScript function. When we call the new JavaScript function, the connect() function is going to automatically call our action creator, take the action that gets returned and automatically call the dispatch() function for us.
So by passing the action creator into the connect() function, whenever we call the action creator that gets added to our props object, the function is going to automatically take the action that gets returned and throw it into dispatch function for us.
All this is happening behind the scenes and you don't really have to think about it when using the connect() function.
So thats how redux works, there is a lot of wiring up and its one of the chief complaints I believe people have around this library, so I do understand your sentiment of wanting to pre-configure some of its setup and in this case, in my opinion, the toughest part of the Redux setup which is wiring up the action creators and reducers.
The problem with pre-configuring I am thinking is that the developer still needs to know how to write these functions and then manually hook them together as opposed to how its done in other state management libraries and if that is taken away by some type of pre-configuration process, Redux becomes more magical and harder to troubleshoot I think. Again the action creators and reducers are the biggest challenge in putting together a Redux architecture and so mastering and knowing how to troubleshoot that area almost requires manual setup to do so.

How can I combine two versions of redux-form in one store?

I have a lot of forms and want to gradually, one by one, migrate my forms from 5 to 6 version of redux-form.
I have figured out how to manage dependencies but how can I combine two versions of reducers with one store key form?
You should be able to use the getFormState config property when connecting the form to redux and point it to the corresponding key in the state tree.
When combining the reducer, include both versions but at different keys (I'm not sure how you are managing the the dependencies but you should get the jist):
import { createStore, combineReducers } from 'redux'
import { reducer as formReducerV5 } from 'redux-form-v5'
import { reducer as formReducer } from 'redux-form'
const reducers = {
// ... your other reducers here
form: formReducer,
formV5: formReducerV5
}
const reducer = combineReducers(reducers)
const store = createStore(reducer)
Then to use the v5 reducer you override the default form key:
const yourFormContainer = reduxForm({
form: 'myForm'
getFormState: state => state.formV5
})(YourForm);
Forms that have been migrated to v6 can just use the default getFormState behaviour and eventually you will be able to remove the old reducer.

redux-observable error Uncaught TypeError: Cannot read property 'apply' of undefined

I am using redux-observable in my redux react app. Given below is the code where I wire everything up. I am using redux-dev tools as well.
const rootEpic = combineEpics(
storeEpic
);
const epicMiddleware = createEpicMiddleware(rootEpic);
//Combine the reducers
const reducer = combineReducers({
syncSpaceReducer,
routing: routerReducer
});
const loggerMiddleware = createLogger();
const enhancer = compose(
applyMiddleware(thunkMiddleware, loggerMiddleware, epicMiddleware),
DevTools.instrument()
);
const store = createStore(reducer, enhancer);
My epic has the following code
export const storeEpic = action$ =>
action$.ofType('FETCH_STORES')
.mapTo({
type: 'FETCHHING_STORES'
});
Now when I run the app I get the following error
Uncaught TypeError: Cannot read property 'apply' of undefined
What am I doing wrong here?
I'm not sure it's possible for us to say. The code you provided all seems fine. The easiest way to know what's wrong is to look at the stack trace for that error. Where does it happen? What led up to it happening? Set a breakpoint there or use "Pause on exceptions" in your debugger to see what exactly is trying to call apply on a variable that is undefined--why is it undefined? That's ultimately the real question.
Edit based on your comments.
The problem is that what you're passing to combineEpics isn't actually your epic, it's undefined. Often that happens when your epic import has a typo or is not exported as you expect. Pause your debugger right before combineEpics and you'll see which one is undefined (or all of them).
Just import storeEpic in the file where combineEpics is called and it will work fine

Resources