compose.apply(...) is not a function - redux

I keep getting this error and im not sure what im doing wrong - It looks pretty much exact to the docs except it doesnt work.
import {createStore , combineReducers, applyMiddleware} from 'redux'
import counterReducer from './ducks/counter'
const reducer = combineReducers({
counter: counterReducer
})
let preloadedState
const preloadedString = localStorage.getItem("prev")
if(preloadedString){
preloadedState = JSON.parse(preloadedString)
}
function thisIsSomeMiddleware(){
console.log('hey yo');
}
const middleware = applyMiddleware(thisIsSomeMiddleware);
const store = createStore(reducer, preloadedState , middleware)
export default store
Can anyone see whats going wrong here?

applyMiddleware needs a middleware so it needs to be a function that looks like this: store=>next=>action=>next(action)

Related

ReduxSaga makes my website re-render infinite

Im using Redux-Saga and Redux-Thunk, this is store I have configured, but it makes my website re-render infinitely. Can u tell me what should i do to solve that? Thank u.
Store.js
import { createStore, applyMiddleware, compose } from 'redux'
import createSagaMiddleware from '#redux-saga/core'
import EmployeeReducer from './reducers/EmployeeReducer'
import thunk from 'redux-thunk'
import axiosMiddleware from "redux-axios-middleware";
import HttpService from "app/services/HttpService";
import RootReducer from './reducers/RootReducer'
import {getEmployeeList} from './saga'
const initialState = {};
const sagaMiddleware = createSagaMiddleware()
const middlewares = [
thunk,
sagaMiddleware,
axiosMiddleware(HttpService.getAxiosClient())
];
export const Store = createStore(
RootReducer,
initialState,
compose(
applyMiddleware(...middlewares)
)
);
sagaMiddleware.run(getEmployeeList)
This is saga.js where i import getEmployeeList
import { call, cancel, put, takeEvery, takeLatest } from 'redux-saga/effects'
import axios from 'axios'
import { GET_EMPLOYEE_LIST } from './actions/EmployeeActions'
import ConstantList from '../../app/appConfig'
const API_PATH = ConstantList.API_ENPOINT + "/employees"
export function* getEmployeeList() {
yield takeEvery(GET_EMPLOYEE_LIST, workEmployeeList)
}
export function* workEmployeeList() {
console.trace("hello");
try {
const url = API_PATH + '/search'
const response = yield call(axios.post, url, {})
yield put({
type: GET_EMPLOYEE_LIST,
payload: response.data.data
})
} catch (error) {
console.log("Request failed!")
}
}
The issue is that you are using the same action type to start the saga & to store the results to redux store.
// here you are waiting for GET_EMPLOYEE_LIST to trigger the saga
yield takeEvery(GET_EMPLOYEE_LIST, workEmployeeList)
// here you are using the same action type to store
// response data to redux store
yield put({
type: GET_EMPLOYEE_LIST,
payload: response.data.data
})
Because of that every time you finish fetching data another saga is triggered.
What you want is to have another action type to store the data in redux store like FETCH_EMPLOYEE_LIST_SUCCESS. Don't forget to update your reducer condition to use the correct action type as well.
You built yourself an infinite loop here:
yield takeEvery(GET_EMPLOYEE_LIST, workEmployeeList)
this means: "every time, GET_EMPLOYEE_LIST is dispatched, execute workEmployeeList"
And in workEmployeeList you have:
yield put({
type: GET_EMPLOYEE_LIST,
payload: response.data.data
})
this means "dispatch GET_EMPLOYEE_LIST".
So 1. leads to 2. and 2. leads to 1.
I can't really suggest anything to fix this as this is missing a lot of building blocks to work in the first place.
But what I can tell you is that we as Redux maintainers really recommend against using sagas for tasks like data fetching.
If you want to know about the backgrounds, I would recommend you watch the evolution of Redux Async Logic.
But generally, seeing you are just getting into Redux, my advice would be to really take a step back and go through our official Redux Tutorial first.
Not only shows it modern (post-2019) Redux which is about 1/4 of the code you are writing here and a lot less confusing, but it also shows multiple different approaches to data fetching.

How can I see my state in Redux Dev Tools (Extension)?

I'm having trouble seeing my state in the Redux Dev Tools. I added the code from zalmoxisus into my createStore, but nothing is displayed. In my reducers I'm also returning the state as a default (using switch case) but still nothing is displayed in state. Can anyone help with this?
try this to use this:
window.devToolsExtension ? window.devToolsExtension() : f => f
instead of:
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
import {combineReducers} from "redux";
import gamesReducer from ... //
const rootReducer = combineReducers({
gamesReducer
});
export default rootReducer;
You used rootReducer like this right?
If it is try redux-devtools-extension package, easy to setup.
Try this
import { createStore, applyMiddleware, compose } from 'redux'
import reduxImmutableStateInvariant from 'redux-immutable-state-invariant'
import thunk from 'redux-thunk'
import rootReducer from '../reducers'
export const middleware = [thunk]
export default function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
compose(
applyMiddleware(thunk, reduxImmutableStateInvariant()),
window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f,
),
)
}

How to run redux devtools with redux saga?

Trying to run reduxdevtools with redux saga:
Getting this error:
Error
Before running a Saga, you must mount the Saga middleware on the Store using applyMiddleware
This is my jscode:
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
How can I run this devtool with saga? Alternatively what would work otherwise?
codepen
I've used redux-devtools-extension package as described here, redux-devtools-extension documentation.
After adding the package, I've replaced the store definition with this:
const store = createStore(
reducer,
composeWithDevTools(
applyMiddleware(sagaMiddleware)
)
);
Fixed Codepen Link
The previous answer (by trkaplan) uses an imported method composeWithDevTools from 'redux-devtools-extension' package.
If you don't want to install this package, you may use this code (based on the docs):
const composeEnhancers = typeof window === 'object' && window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] ?
window['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__']({ }) : compose;
const enhancer = composeEnhancers(
applyMiddleware(thunkMiddleware, sagaMiddleware, /*other middleware*/),
/* other store enhancers if any */
);
const emptyReducer = () => {};
const store = createStore(emptyReducer, enhancer);
This is how you configure your redux, redux-devtool-extension and redux-saga for the real projects..
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import createSagaMiddleware from 'redux-saga';
import rootReducer from '../reducers';
import rootSaga from '../sagas';
const configureStore = () => {
const sagaMiddleware = createSagaMiddleware();
return {
...createStore(rootReducer, composeWithDevTools(applyMiddleware(sagaMiddleware))),
runSaga: sagaMiddleware.run(rootSaga),
};
};
export default configureStore;
Incase Compose of Redux is used. Then below code is useful.
Step 1: Add chrome Redux DevTools extension.
step 2: npm install redux-devtools-extension.
import { composeWithDevTools } from 'redux-devtools-extension';
const store = createStore(
reducer,
compose(
applyMiddleware(sagaMiddleware),
composeWithDevTools(),
),
);

What is the correct way to combine redux-thunk and redux-batched-actions?

What is the correct way to plug redux-batched-actions into my existing Redux store? I am completely confused by the Redux middleware API.
Currently I am using redux-thunk and redux-little-router.
Here is the code source that creates my Redux store:
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
import thunk from 'redux-thunk'
import { routerForBrowser } from 'redux-little-router'
import reducers from './store'
import routes from './routes'
const { reducer, middleware, enhancer } = routerForBrowser({ routes })
// Combine all reducers and instantiate the app-wide store instance
const allReducers = combineReducers({ ...reducers, router: reducer })
// Build middleware (if devTools is installed, connect to it)
const allEnhancers = (window.__REDUX_DEVTOOLS_EXTENSION__
? compose(
enhancer,
applyMiddleware(thunk, middleware),
window.__REDUX_DEVTOOLS_EXTENSION__())
: compose(
enhancer,
applyMiddleware(thunk, middleware)))
// Instantiate the app-wide store instance
const initialState = window.initialReduxState
const store = createStore(
allReducers,
initialState,
allEnhancers
)
The redux-batched-actions documentation exposes two usages: enableBatching and batchDispatchMiddleware. Which one should I use in my case?
Answering my own question after the return of my expedition into the fabulous source code of redux, redux-thunk, redux-batched-actions, ...
The correct way to do it seems to be using batchDispatchMiddleware, like this:
import { batchDispatchMiddleware } from 'redux-batched-actions'
// ...
const allEnhancers = (window.__REDUX_DEVTOOLS_EXTENSION__
? compose(
enhancer,
applyMiddleware(batchDispatchMiddleware, thunk, middleware),
window.__REDUX_DEVTOOLS_EXTENSION__())
: compose(
enhancer,
applyMiddleware(batchDispatchMiddleware, thunk, middleware)))
Note: I don't know if I could dispatch batched thunks, though. I don't do that in my current application. Use at your own risk!

Integrating redux with aws-appsync

Is there any way to integrate redux with aws-appsync in react-native?
If there is can you give me hint or clue on how to do it? I'm having a hard time integrating it. Thank you in advance.
I think you should be able to connect your own redux store as is detailed in their documentation. Basically create your own and use connect(mapStateToProps, mapDispatchToProps) from react-redux to connect your components.
const MyComponent = props => <h1>HI!</h1>
const ReduxConnected = connect(mapStateToProps, mapDispatchToProps)(MyComponent)
const GraphQLConnected = graphql(gql`query { hi }`)(ReduxConnected)
And then at the root of your application have
import AWSAppSyncClient from "aws-appsync";
import { Provider as ReduxProvider } from 'react-redux'
import { graphql, ApolloProvider } from 'react-apollo';
import { Rehydrated } from 'aws-appsync-react';
import { createStore } from 'redux'
const client = new AWSAppSyncClient({...})
const store = createStore({...})
const ConnectedApp = () =>
<ApolloProvider client={client}>
<Rehydrated>
<ReduxProvider store={store}>
<App />
</ReduxProvider>
</Rehydrated>
</ApolloProvider>
I haven't had a chance to try this setup but I will soon and will edit with any findings. In the meantime here is a link showing how to build a full RN app with AppSync that uses MobX instead of Redux (https://github.com/dabit3/heard) that may also be a good place to start.

Resources