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

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

Related

Why is immer complaining about computed properties?

So based on a recent answer, I've started using ReduxStarterKit, which uses Immer in it's slice function. Overall, I think the basic idea is brilliant.
Unfortunately, when I try to actually make use of immer to make my life easier, I run into issues. I've tried to simplify what I'm doing using my test reducer, and I'm still getting the same basic problem. I've also turned off all my middleware (ElectronRedux) to make sure it's not a problem there. The following is a simplified test reducer I'm using for testing:
const CounterSlice = createSlice({
name: 'counter',
reducers: {
increment: (state)=>{state.value = state.value + 1},
decrement: (state)=>{state.value = state.value - 1}
},
initialState: { value: 0 },
})
The code above is pretty simple, and as far as I can tell exactly what Immer/ReduxStarterKit wants me to write. Despite this, when I call the code I'm getting an error: Uncaught Error: Immer drafts cannot have computed properties
What am I doing wrong?
Edit:
I just put together a simple demo app, just for the purposes of testing the basics. The counter slice has coded here works perfectly. I guess this is an interaction between Immer and another package -- just not sure where to go about debugging which one. Is it a redux version issue, is it electron, electron redux, typescript, webpack, the list goes on and (painfully) on.
I may have to recreate my basic app environment and test this one painful step at a time. Ugh!
Turns out the problem wasn't in the code I was sharing, it was way over to the side when I was setting up my initial state. Electron was manipulating the data I sent back and forth via getState(), adding getter & setter methods. Those getter & setter methods were (quite rightly) triggering this error.
const initialState = remote.getGlobal('state');
console.log("initial state: ", initialState);
const store = CreateStore({initialState:{...initialState}, main: false})
Expected log output: { counter: { value: 1 } ...rest}, but actual output was { counter: {value: 1, getValue: function(), setValue: function() }, getCounter: function(), setCounter: function(), ...rest.
Woops. Now I just need to 'clean' my state up, since apparently state storage somehow persists this failure. And then figure out how to strip the (nested!) getters/setters. Ugh.
Edit: Rather than stripping the getters / setters, I just needed to use the built-in getInitialStateRenderer from electron-redux. So change the above code to:
const initialState = getInitiateStateRenderer()
const store = CreateStore({initialState: initialState, main: false})

Redux - Providing reducer function for create store error

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".

correct registartion of epics in #angular-redux/store configureStore 9 ver

I have moved own project to angular 6, #angular-redux/store 9 from 5 version. All was fine, but way for registrate epics in middleware not worked. I remove all epics from middleware except logger and startup was fine with all actions executed. Then i try add one epic and get error like
TypeError: action$.pipe is not a function
at SecurityUserEpics.loadSecurityUser (security-user.epic.ts:31)
at combineEpics.js:19
Then i try to solve this and search many examples and docs about, but cant find solution. After deciding to ask question here and while prepare code for question the solution was found. Soo, i post here that solution in hope that this will save time for someone.
epic:
loadSecurityUser = (action$) => {
debugger;
// here i have object of type : {getState: ƒ, dispatch: ƒ} and thats was pain from older version. pipe helps!
return action$.pipe(
ofType(SecurityUserActions.LoadSecurityUsers),
switchMap(q => this._dataSrv.getUserInfo()
.pipe(map(data => {
localStorage.setItem('isNeedRelogin', '0');
return this._securityUserActions.loadSecurityUserComplete(data);
}))));
}
And final config store:
const epicMiddleware = createEpicMiddleware();
const middleware = [epicMiddleware];
middleware.push(createLogger());
ngRedux.configureStore(combinedReducer, INITIAL_STATE, middleware, storeEnhancers);
const rootEpic = combineEpics(this._securityUserEpics.loadSecurityUser);
// this is new way of middleware registration
epicMiddleware.run(rootEpic);
Use provideStore instead configureStore, for example -
export const combinedEpics = combineEpics(
pingEpic,
fetchUserEpic
);
//replace ngRedux.configureStore with:
const epicMiddleware = createEpicMiddleware();
const store = createStore(
combinedReducer,
INITIAL_STATE,
applyMiddleware(createLogger(), epicMiddleware),
);
ngRedux.provideStore(store);
epicMiddleware.run(combinedEpics);
more information about epics - https://redux-observable.js.org/docs/basics/Epics.html

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.

Redux Thunk / Eslint erro

I'm trying to build a React + Redux app, and I'm using Redux Thunk.
One of my action creators looks like this:
import api from '../api';
export const FETCH_BOOKS = 'FETCH_BOOKS';
export default () => dispatch =>
api
.books()
.perPage(-1)
.then(books =>
dispatch(books => ({
type: FETCH_BOOKS,
books,
}))
)
.catch(error =>
dispatch(e => ({
type: 'ERROR',
error: e,
}))
);
But when I run yarn run build:production I get the error(s):
ERROR in ./scripts/ll-app/actions/fetch-books.js
/Users/joneslloyd/resources/assets/scripts/ll-app/actions/fetch-books.js
9:11 warning 'books' is defined but never used no-unused-vars
11:9 error Expected an assignment or function call and instead saw an expression no-unused-expressions
11:9 error 'books' is already declared in the upper scope no-shadow
17:12 warning 'error' is defined but never used no-unused-vars
19:9 error Expected an assignment or function call and instead saw an expression no-unused-expressions
19:9 error 'error' is already declared in the upper scope
However, I want to pass the books array (returned from the async api call) to the dispatch (anonymous function passed to dispatch) to then include said books array in the action, which the reducer will receive.
Am I doing something wrong here?
Even when I rename the inner reference to books it doesn't help.
It's possible I'm overlooking something in ES6 here.. But I basically want to take the books array returned from the api call (as a parameter of the then method), and then pass it into the dispatch function inside of that, as a parameter of the anonymous function I'm passing in.
Any help with this would be excellent. Thanks!
I'm not sure if this is the source of the problem, but why do you need the inner ref to books at all? Your error msg/linter is complaining about that.
...
api
.books()
.perPage(-1)
.then(books =>
dispatch({
type: FETCH_BOOKS,
books,
})
).catch(error => dispatch({type: ERROR, error}))
why won't the above do what you want?
no function in the dispatch necessary here.
dispatch needs a plain action. A function in dispatch is giving you the error.
When you see function in dispatch in the docs, those functions are function calls that are just returning the action.
export someActionCreator = () => ({type: ACTION, payload})
dispatch(someActionCreator());
Your functions are just statements and are not returning the action to the dispatch. which would be more akin to something like
export someActionCreator = () => ({type: ACTION, payload})
dispatch(someActionCreator);
see the difference?
Hope this helps!

Resources