Cannot read property 'getState' of undefined - Redux - javascript

I've got a React app and now I use redux. The app worked, but now I'm getting the error:
Uncaught TypeError: Cannot read property 'getState' of undefined
at new Provider (Provider.js:25)
at vf (react-dom.production.min.js:132)
at Og (react-dom.production.min.js:167)
at Tg (react-dom.production.min.js:180)
at bi (react-dom.production.min.js:232)
at ci (react-dom.production.min.js:233)
at Di (react-dom.production.min.js:249)
at Yh (react-dom.production.min.js:248)
at Xh (react-dom.production.min.js:245)
at qf (react-dom.production.min.js:243)
Can someone help here?
Code:
store.js:
import {
combineReducers,
createStore
} from 'redux';
import campaignReducer from './campaign/reducer';
const reducer = combineReducers({
campaign: campaignReducer
});
const enhancedCreateStore = createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default enhancedCreateStore;
App.jsx:
import React from 'react';
import ReactDOM from 'react-dom';
import {
HashRouter as Router
} from 'react-router-dom';
import {
Provider
} from 'react-redux';
// tell webpack about all used svg images
/* eslint-disable */
import svgSprite from './js/services/helper';
/* eslint-enable */
import Shop from './js/components/shop';
import {
store
} from './js/store/store';
// render the {React.Component}
ReactDOM.render( <
Provider store = {
store
} >
<
Router >
<
Shop / >
<
/Router> < /
Provider > ,
document.querySelector('#order-form')
);
Shop.jsx (connect part):
const stateMapper = ({
isOpen,
message,
showOkBtn,
showCancelBtn
}) => ({
isOpen,
message,
showOkBtn,
showCancelBtn
});
const dispatchMapper = dispatch => ({
onSetModalOpen: options => dispatch(Action.openCampaignModal(options)),
onSetModalClosed: () => dispatch(Action.closeCampaignModal())
});
export default connect(
stateMapper,
dispatchMapper
)(Shop);
helper.js:
export const createReducer = (initialState, handlers) => (state = initialState, action) => {
// eslint-disable-next-line
if (action.type in handlers) {
return handlers[action.type](state, action);
}
return state;
};
export const multiUse = (reducer, name = '') => (state = null, action) => {
if (action.name !== name) return state;
return reducer(state, action);
};
action.js:
export const OPEN_CAMPAIGN_MODAL = 'OPEN_CAMPAIGN_MODAL';
export const CLOSE_CAMPAIGN_MODAL = 'CLOSE_CAMPAIGN_MODAL';
export const SET_CAMPAIGN = 'SET_CAMPAIGN';
export const openCampaignModal = ({
message,
showOkBtn,
showCancelBtn
}) => ({
type: OPEN_CAMPAIGN_MODAL,
modal: {
isOpen: true,
message,
showOkBtn,
showCancelBtn
}
});
export const closeCampaignModal = () => ({
type: CLOSE_CAMPAIGN_MODAL,
modal: {
isOpen: false
}
});
export const setCampaign = name => ({
type: SET_CAMPAIGN,
selected: name
});
reducer.js:
import {
createReducer
} from '../helper';
import * as Action from './actions';
export default createReducer({
modal: {
isOpen: false,
message: null,
showOkBtn: true,
showCancelBtn: false
},
selected: ''
}, {
[Action.OPEN_CAMPAIGN_MODAL]: (state, {
isOpen,
message,
showOkBtn,
showCancelBtn
}) =>
Object.assign({}, state, {
modal: {
isOpen,
message,
showOkBtn,
showCancelBtn
}
}),
[Action.CLOSE_CAMPAIGN_MODAL]: (state, {
isOpen
}) =>
Object.assign({}, state, {
modal: {
isOpen
}
}),
[Action.SET_CAMPAIGN]: (state, action) =>
Object.assign({}, state, {
selected: action.selected
})
});
What is the problem here? I did a lot of debugging and the redux-dev-tools in chrome also seems to show an initialized redux state (although I cannot see any state).

You are export default in store.js, but then you use a named import:
import {
store
} from './js/store/store';
Change to this:
import store from './js/store/store';

Related

Reducer can't read action.type REDUX

I'm new to redux and I can't figure out what I'm doing wrong
accessTokenActions.js file
import { getAccessToken } from '../../utils/spotifyAuth';
import * as types from '../consts/types';
export const fetchAccessTokenRequest = () => ({
type: types.FETCH_ACCESS_TOKEN,
});
export const fetchAccessTokenSuccess = (data) => ({
type: types.FETCH_ACCESS_TOKEN_SUCCESS,
payload: {
data,
},
});
export const fetchAccessTokenError = (error) => ({
type: types.FETCH_ACCESS_TOKEN_ERROR,
payload: {
error,
},
});
export const fetchAccessToken = () => async (dispatch) => {
dispatch(fetchAccessTokenRequest());
try {
const response = await getAccessToken();
if (!response) {
throw Error();
}
return dispatch(fetchAccessTokenSuccess(response.data));
} catch (err) {
return dispatch(fetchAccessTokenError(err.response.data));
}
};
accessTokenReducer.js file
import * as types from '../consts/types';
const initialState = {
accessToken: null,
isLoading: false,
error: null,
};
const accessTokenReducer = (state = initialState, action) => {
switch (action.type) {
case types.FETCH_ACCESS_TOKEN:
return {
...state,
isLoading: true,
};
case types.FETCH_ACCESS_TOKEN_SUCCESS:
return {
...state,
accessToken: action.payload.access_token,
};
case types.FETCH_ACCESS_TOKEN_ERROR:
return {
...state,
accessToken: null,
isLoading: false,
error: action.payload.error,
};
default:
return state;
}
};
export default accessTokenReducer;
index.js file
import { combineReducers } from 'redux';
import accessTokenReducer from './accessTokenReducer';
const rootReducer = combineReducers({
accessToken: accessTokenReducer,
});
export default rootReducer;
configureStore.js file
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers/index';
const configureStore = () => {
const middlewares = [thunk];
const store = createStore(
rootReducer,
compose(
applyMiddleware(...middlewares),
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__(),
),
);
return store;
};
export default configureStore;
const/types file
export const FETCH_ACCESS_TOKEN = 'FETCH_ACCESS_TOKEN';
export const FETCH_ACCESS_TOKEN_SUCCESS = 'FETCH_ACCESS_TOKEN_SUCCESS';
export const FETCH_ACCESS_TOKEN_ERROR = 'FETCH_ACCESS_TOKEN_ERROR';
I also have a selectors file(which I think doesn't affect the code cause I don't call any functions from there)
I keep getting TypeError: Cannot read property 'type' of undefined error in my switch statement at the reducer function, I'm currently studying the redux documentation but I can't figure out what's going on
Any help would be greatly appreciated

Function is not getting called anymore, when trying to dispatch a type

I am currently trying to access my data using the Spotify API. This works very well. Thats the function I am using to get my Data. I assume the other stuff is not important. I can post that, if you need that.
export const getSpotifyUser = (access_token:string) =>{
setAuthorizationHeader(access_token)
axios.get('https://api.spotify.com/v1/me').then((res) => {
console.log(res.data)
})
}
I have set up a redux store and trying to put the credentials into the store, by dispatching the right type (SET_USER).
export const getSpotifyUser = (access_token:string) => (dispatch: any) => {
console.log("function is not called") // Function is not even called why ?
setAuthorizationHeader(access_token)
axios.get('https://api.spotify.com/v1/me').then((res) => {
console.log(res.data)
dispatch ({
type: SET_USER,
payload: res.data
})
}
but as soon as I use dispatch, the function is no longer called.
I really do not see my mistake. Is that a typescript error ?. ( I am using react typescript)
store.js
import { createStore, applyMiddleware } from 'redux'
import rootReducer from './rootReducer'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'
const store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(thunk))
)
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
export default store
rootReducer.ts
import { combineReducers } from 'redux'
import userReducer from './User/userReducer'
const rootReducer = combineReducers({
user: userReducer,
})
export default rootReducer
userReducer.ts
import { AnyAction } from 'redux'
import { SET_USER } from './userTypes'
interface Credentials {
username: string
email: string
profilepicture: string
id: number
}
interface InitialState {
authenticated: boolean
loadding: boolean
credentials?: Credentials
}
const initialState: InitialState = {
authenticated: false,
loadding: false,
credentials: {} as Credentials,
}
const reducer = (state = initialState, action: AnyAction) => {
switch (action.type) {
case SET_USER: {
return {
...state,
loading: false,
credentials: action.payload,
}
}
default:
return state
}
}
export default reducer
Login.tsx ( I am making the login here. It is working fine, if am not using dispatch
import { IonButton } from '#ionic/react'
import React, { useEffect } from 'react'
import {
getAuthorizeHref,
getHashParams,
removeHashParamsFromUrl,
getSpotifyUser,
} from '../../Helpers/login'
const Login: React.FC = () => {
// const user = useSelector((state: RootState) => state.user.credentials)
useEffect(() => {
const hashParams = getHashParams()
const access_token = hashParams.access_token
// const expires_in = hashParams.expires_in
removeHashParamsFromUrl()
getSpotifyUser(access_token)
}, [])
return (
<IonButton onClick={() => window.open(getAuthorizeHref(), '_self')}>
)}
export default Login
since you're using typescript with react, I believe you have added the getSpotifyUser function to your interface, now if you want to access that i think you should call it like this
props.getSpotifyUser(access_token)
and finally add it to your connect as a dispatch function that's wrapping your component
your login component should be like this one
import { IonButton } from '#ionic/react'
import React, { useEffect } from 'react'
import { connect } from 'react-redux'
import {
getAuthorizeHref,
getHashParams,
removeHashParamsFromUrl,
getSpotifyUser,
} from '../../Helpers/login'
interface ILogin {
getAuthorizeHref: () => any;
getHashParams: () => any;
removeHashParamsFromUrl: () => any;
getSpotifyUser: (access_token) => any;
}
const Login: React.FC = (props: ILogin) => {
// const user = useSelector((state: RootState) => state.user.credentials)
useEffect(() => {
const hashParams = props.getHashParams()
const access_token = hashParams.access_token
// const expires_in = hashParams.expires_in
props.removeHashParamsFromUrl()
props.getSpotifyUser(access_token)
}, [])
return (
<IonButton onClick={() => window.open(props.getAuthorizeHref(), '_self')}>
)}
export default connect(null, {getAuthorizeHref, getHashParams, removeHashParamsFromUrl, getSpotifyUser})(Login)
Basicly Shamim has given the right answer.Any function that uses that dispatch is a redux action, and you have to follow the docs specifically to call that function. You have to use connect to dispatch actions. As an alternative you can use the dispatchHook. If am wrong please please correct me !!!!
Thats the right code I just had to correct Login.tsx
import { IonApp, IonButton } from '#ionic/react'
import React, { useEffect } from 'react'
import { connect } from 'react-redux'
import {
getAuthorizeHref,
getHashParams,
removeHashParamsFromUrl,
getSpotifyUser,
} from '../../Helpers/login'
const style = {
Logo: {
display: 'flex',
justifyContent: 'space-evenly',
color: 'white',
position: 'relative',
top: '70%',
} as const,
}
const Login: React.FC = (props: any) => {
// const user = useSelector((state: RootState) => state.user.credentials)
useEffect(() => {
const hashParams = getHashParams()
const access_token = hashParams.access_token
// const expires_in = hashParams.expires_in
removeHashParamsFromUrl()
console.log('halloeuseeffect')
props.getSpotifyUser(access_token)
console.log('halloeuseeffect')
}, [])
return (
<IonApp>
<IonButton onClick={() => window.open(getAuthorizeHref(), '_self')}>
knsnan
</IonApp>
)
}
export default connect(null, {
getSpotifyUser,
})(Login)

react redux and combine reducers

Hello I am using thunks to get data from my backend
but I am unsure how to do it in my combine reducer
my types:
export const FETCH_SUCESS = 'FETCH_SUCESS';
export const FETCH_FAIL = 'FETCH_FAIL';
export const FETCH_LOADING = 'FETCH_FAIL';
export const FILTER_PRODUCT = 'FILTER_PRODUCT';
my action:
import api from '../../services/api';
import {FETCH_SUCESS,FETCH_FAIL,FETCH_LOADING} from '../constants/fetchTypes';
const fetchSucess = data => ({
type: FETCH_SUCESS,
payload: {
...data
}
});
const fetchStarted = () => ({
type: FETCH_LOADING
});
const fetchFailed = error => ({
type: FETCH_FAIL,
payload: {
error
}
});
export const fetchProduct = () => {
console.log('action')
return dispatch => {
dispatch(fetchStarted());
api
.get('/products')
.then(res => {
dispatch(fetchSucess(res.data));
})
.catch(err => {
dispatch(fetchFailed(err.message));
});
};
};
my reducer:
import {
FETCH_SUCESS,
FETCH_FAIL,
FETCH_LOADING,
} from '../constants/fetchTypes';
const initialState = {
loading: false,
data: [],
error: null
};
export default function productReducer(state = initialState, action) {
switch (action.type) {
case FETCH_LOADING:
return {
...state,
loading: true
};
case FETCH_SUCESS:
return {
...state,
loading: false,
error: null,
data: [...state.data, action.payload]
};
case FETCH_FAIL:
return {
...state,
loading: false,
error: action.payload.error
};
default:
return state;
}
}
my combiner:
import { combineReducers } from 'redux'
import productReducer from './productsFetch.reducer';
export default combineReducers({
});
my store:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
export default function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk)
);
}
my home.js
class HomeProducts extends Component {
componentDidMount() {
this.props.fetchData();
}
render() {
const productItems = this.props.products.map( product => (
<div className="col-md-4 pt-4 pl-2">
<div className = "thumbnail text-center">
<a href={`#${product.id}`} onClick={(e)=>this.props.handleAddToCard(e,product)}>
<p>
{product.name}
</p>
</a>
</div>
<b>{util.formatCurrency(product.price)}</b>
<button className="btn btn-primary" onClick={(e)=>this.props.handleAddToCard(e,product)}>Add to Cart</button>
</div>
)
)
return (
<div className="container">
<div className="row">
{productItems}
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
console.log(state);
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: () => dispatch(fetchProduct())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(HomeProducts);
I have doubt what to use in my combiner
to get the date and the mistakes How I have my loading,data, error
I don't know how I will do it in meu combine redux
I also don't know if I had the best practices in my action and my reducer
In your combiner file just add your reducers as key value pairs like so:
import { combineReducers } from 'redux'
import productReducer from './productsFetch.reducer';
// import anotherReducer from './yourPath';
export default combineReducers({
products: productReducer,
// anotherState: anotherReducer
});
Ideally you should import your actions and pass it your component through your connect method like so then you will be able to access it from your component as props.
import fetchProduct from './pathToYourActionFile';
const mapStateToProps = (state) => {
console.log(state);
};
const mapActionsToProps = {
fetchProduct: fetchProduct
};
export default connect(mapStateToProps, mapActionsToProps)(HomeProducts);
import thunkInject from 'redux-thunk-inject';
const mockStore = configureMockStore([thunkInject()]);
const store = mockStore(mockStore);
const wrapper = mount(<Provider store={store} />);
expect(wrapper).toMatchSnapshot();
to mock a store with thunk, you can inject it as a prop in a component. Or in a reducer, e.g.
import productReducer from '../productReducer';
import {
FETCH_SUCESS,
FETCH_FAIL,
FETCH_LOADING,
} from '../constants/fetchTypes';
describe('product reducer', () => {
it('Should handle FETCH_SUCCESS', () => {
expect(productReducer(store, FETCH_SUCCESS)
).toEqual({
loading: true
});
expect(productReducer(store, FETCH_FAIL).toEqual({
loading: false,
error: action.payload.error})
});

Redux-thunk dispatch function doesn't work on Laravel

I'm using React-Laravel for my project.
The problem is when I tried to use redux-thunk for the asynchronous dispatch function.
My dispatch function won't get executed.
Please do help me figure out this problem.
I have already tried to use promise or redux-devtools-extension library
https://codeburst.io/reactjs-app-with-laravel-restful-api-endpoint-part-2-aef12fe6db02
app.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
import Layout from './jsx/Layout/Layout';
import marketplaceReducer from './store/reducers/marketplace';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const appReducer = combineReducers({
marketplace: marketplaceReducer
});
const rootReducer = (state, action) => {
return appReducer(state, action);
}
const store = createStore(rootReducer, composeEnhancers(
applyMiddleware(logger, thunk)
));
const render = (
<Provider store={store}>
<BrowserRouter>
<Layout />
</BrowserRouter>
</Provider>
);
ReactDOM.render(render, document.getElementById('root'));
marketplace.js (action)
import * as actionTypes from './actionTypes';
import axios from '../../axios';
export const loadMarketplace = () => {
console.log("Load Marketplace");
return {
type: actionTypes.LOAD_MARKETPLACE
};
}
export const successMarketplace = (data) => {
console.log("Success Marketplace");
return {
type: actionTypes.SUCCESS_MARKETPLACE,
data: data
}
}
export const failedMarketplace = () => {
console.log("Failed Marketplace");
return {
type: actionTypes.FAILED_MARKETPLACE
}
}
export const showMarketplace = () => {
console.log("Show Marketplace Action")
return dispatch => {
//This is the problem
//Inside this function, I can't see any console.log, even loadMarketplace() didn't get called.
console.log("Show Marketplace in dispatch");
dispatch(loadMarketplace());
axios.get('/marketplaces')
.then(response => {
dispatch(successMarketplace(response));
})
.catch(error => {
dispatch(failedMarketplace());
});
};
}
marketplace.js (reducer)
import * as actionTypes from '../actions/actionTypes';
const initial_state = {
data: [],
loading: false
}
const loadMarketplace = (state, action) => {
console.log("Load Marketplace Reducer")
return {
...state,
loading: true
};
}
const successMarketplace = (state, action) => {
console.log("Success Marketplace Reducer", action.data)
return {
...state,
loading: false,
data: action.data
};
}
const failedMarketplace = (state, action) => {
return {
...state,
loading: false
};
}
const reducer = (state = initial_state, action) => {
//This is called when the first init, never got it through showMarketplace() function.
console.log("Marketplace Reducer", action);
switch (action.type) {
case actionTypes.LOAD_MARKETPLACE: return loadMarketplace(state, action);
case actionTypes.SUCCESS_MARKETPLACE: return successMarketplace(state, action);
case actionTypes.FAILED_MARKETPLACE: return failedMarketplace(state, action);
default: return state;
}
}
export default reducer;
Marketplace.js (jsx view)
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../../../store/actions';
class Marketplace extends Component {
componentDidMount() {
console.log('[ComponentDidMount] Marketplace')
this.props.showMarketplace();
}
render() {
return (
<React.Fragment>
Marketplace
</React.Fragment>
);
}
}
const mapDispatchToProps = dispatch => {
return {
showMarketplace: () => dispatch(actions.showMarketplace)
};
}
export default connect(null, mapDispatchToProps)(Marketplace);
This is the result of my console.log (when loading the first time for Marketplace.js)
Please do help, I've been struggling for 2 hours or more, only because of this problem. (This is my first time using React-Laravel).
Thank you.
I already found the problem. It is not redux-thunk problem.
It is actually a normal Redux problem we found anywhere.
Marketplace.js (jsx view)
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../../../store/actions';
class Marketplace extends Component {
componentDidMount() {
console.log('[ComponentDidMount] Marketplace')
this.props.showMarketplace();
}
render() {
return (
<React.Fragment>
Marketplace
</React.Fragment>
);
}
}
const mapDispatchToProps = dispatch => {
return {
showMarketplace: () => dispatch(actions.showMarketplace) //THIS IS THE PROBLEM, IT IS NOT EXECUTING PROPERLY. THIS ONE SHOULD BE
showMarketplace: () => dispatch(actions.showMarketplace()) //SHOULD BE LIKE THIS.
};
}
export default connect(null, mapDispatchToProps)(Marketplace);
Edited: I think it is something about thunk is not added right to redux.
First of all try to add only thunk.
const store = createStore(rootReducer, composeEnhancers(
applyMiddleware(thunk)
));
If it works, maybe try to change the order of them.

Redux-thunk: `dispatch is not a function`

So, I'm having an issue with an action returning the above mentioned error (See attached image), instead of updating redux state as expected. What am I overlooking here?
actionCreators.js
export function userToken(token) {
console.log('userToken has been fired');
return (dispatch) => {
dispatch({
type: 'Graphcool_Token',
payload: token
});
}
}
App.js
....
// Root Query
const allPostsCommentsQuery = graphql(All_Posts_Comments_Query, {
options: {
cachePolicy: 'offline-critical',
fetchPolicy: 'cache-first',
},
});
export const mapDispatchToProps = (dispatch) => {
return bindActionCreators(actionCreators, dispatch);
}
export default compose(
allPostsCommentsQuery,
connect(mapDispatchToProps)
)(Main);
Reducer
var tokenDetails = function(state, action) {
if (state === undefined) {
state = [];
}
switch (action.type) {
case 'Graphcool_Token':
const newState = [action.payload];
return newState;
default:
return state;
}
}
export default tokenDetails;
LoginUser.js
signinUser: function(emailID, passwordID) {
const email = emailID;
const password = passwordID;
this.props.client.mutate({
mutation: signinUser_Mutation,
variables: {
email,
password,
},
options: {
cachePolicy: 'offline-critical',
fetchPolicy: 'cache-first',
},
})
.then(this.updateStateLoginDetails)
.catch(this.handleSubmitError);
},
updateStateLoginDetails: function({data}) {
this.props.userToken(data.signinUser.token);
},
store.js
import { createStore, applyMiddleware, compose } from 'redux';
import { persistStore, autoRehydrate} from 'redux-persist';
import { syncHistoryWithStore } from 'react-router-redux';
import { browserHistory } from 'react-router'
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
import client from './apolloClient';
import localForage from 'localforage';
const middlewares = [thunk, client.middleware()];
const enhancers = compose(
applyMiddleware(...middlewares),
(typeof window.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined' || process.env.NODE_ENV !== 'production') ? window.__REDUX_DEVTOOLS_EXTENSION__() : (f) => f,
autoRehydrate(),
);
const store = createStore(
rootReducer,
{}, // initial state
enhancers
);
// begin periodically persisting the store
persistStore(store, {storage: localForage});
export const history = syncHistoryWithStore(
browserHistory,
store
);
if(module.hot) {
module.hot.accept('./reducers/', () => {
const nextRootReducer = require('./reducers/index').default;
store.replaceReducer(nextRootReducer);
});
}
export default store;
The first argument you should pass to connect is mapStateToProps, which is a function that receives the state and component props.. You should add null there if you don't need it:
connect(null, mapDispatchToProps)(Main)
BTW, generally speaking, you don't need bindActionCreators.. usually returning an object is enough, like:
const mapDispatchToProps = {
someActionName,
someOtherAction,
}

Categories