I wrote a simple counter app. I tried to add a saga middleware to log actions. Very basic app, but i nice structure.
When I add a middleware something went wrong: I had the error:
redux-saga-core.esm.js:1442 Uncaught Error: Before running a Saga, you must mount the Saga middleware on the Store using applyMiddleware
at Function.sagaMiddleware.run (redux-saga-core.esm.js:1442)
at createAppStore (Store.tsx:66)
at eval (Store.tsx:70)
at Module../src/store/Store.tsx (bundle.js:1175)
at __webpack_require__ (bundle.js:20)
at eval (App.tsx:6)
at Module../src/components/App.tsx (bundle.js:1127)
at __webpack_require__ (bundle.js:20)
at eval (index.tsx:6)
at Module../src/index.tsx (bundle.js:1151)
I found the problem is the initialiseSagaMiddleware.run(sagaLogger);
but why? It comes just after createStore...
Here my store:
/**
* This is the global store, where the magic appens. Here I have a redurcer who generates
* the new application state and the global state.
* Store = cotainer of reducer and state.
*/
import react from "react";
import { createStore, applyMiddleware, } from "redux";
import {IState,IAction, actionType} from '../types/types'
import createSagaMiddleware from "redux-saga";
import {sagaLogger} from '../middleware/sagaLogger'
const initialiseSagaMiddleware = createSagaMiddleware();
/**
* Application initial state. TODO: may be loaded from an API?
*/
const initialState : IState = {
count: -10
}
/**
* Reducer: function that create a new state. I must be a pure function, no side effects.
* It works only on his parameter and return the new state. Reducer parameter are always the same.
* @param state application global state, ad default it has initialState value.
* @param action action fired by components.
*/
const reducer = (state: IState = initialState, action: IAction): IState => { //Set default to initialState
// console.log(state, action);
const newState : IState = { count: state.count}
switch(action.type){
case actionType.INCREMENT:
newState.count= newState.count+1;
break;
case actionType.DECREMENT:
newState.count=newState.count-1;
break;
default:
newState.count= newState.count;
break;
}
return newState;
};
/**
* AppStore is my store. createStore create my Redux Store.
* TODO: change any to <IState,IAction>
* For use with redux dev tool use: storeEnhancers, compose
*/
const sagaMiddleware = createSagaMiddleware();
const createAppStore = (): any => {
const Store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
);
initialiseSagaMiddleware.run(sagaLogger);
return Store;
}
export const AppStore = createAppStore();
Here my app.tsx
import React from 'react'
import {Provider} from 'react-redux'
import {AppStore} from "../store/Store";
import Counter from "./counter";
/**
* Provider is part of the Redux magic. It connect react to redux providing to all the children components (all levels) the state.
*/
export default function App():JSX.Element {
return (
<Provider store = {AppStore}>
<div>
<Counter />
</div>
</Provider>
);
}
Here my banbel.rc (I had to define env preset):
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"browsers": [
"last 2 Chrome versions"
]
}
}
],"@babel/react","@babel/Typescript"]
}
I hope my counter works and action will be logged on the console.
You are creating two saga middlewares and applying one to the store and running your sagas on the other. Remove the const initialiseSagaMiddleware = createSagaMiddleware();
and change createAppStore
to:
const sagaMiddleware = createSagaMiddleware();
const createAppStore = (): any => {
const Store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
);
// use the same saga middleware that you have enhanced your store with
sagaMiddleware.run(sagaLogger);
return Store;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With