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.