45
votes

Not sure why I'm getting the following errors.

I'm just setting up my store, actions and reducers, I haven't called dispatch on anything yet.

Expected

App runs fine, Redux state is not updated

Results

enter image description here

src/index.js
import React from 'react'
import ReactDOM from 'react-dom'

import { createStore, applyMiddleware, compose } from 'redux'
import { Provider } from 'react-redux'
import thunk from 'redux-thunk'
import reducer from './reducer'

import App from './App'
import css from './coinhover.scss'

const element = document.getElementById('coinhover');

const store = createStore(reducer, compose(
    applyMiddleware(thunk),
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
));

ReactDOM.render(
    <Provider store={ store }>
        <App />
    </Provider>, element);
src/reducer/index.js
import { combineReducers } from 'redux'
import { coins } from './coins'

export default combineReducers({
    coins
});
src/reducer/actions/coins.js
import * as api from '../../services/api'
import { storage, addToPortfolio } from '../../services/coinFactory'

export const ADD_COIN = 'ADD_COIN'

export function getCoin(coin) {
    return dispatch => {
        api.getCoin(coin)
            .then((res_coin)  => addToPortfolio(res_coin))
            .then((portfolio) => dispatch(updatePortfolio(portfolio)));
    }
}

export function updatePortfolio(portfolio) {
    return {
        type: ADD_COIN,
        portfolio
    }
}
finally src/reducer/coins/index.js
import { ADD_COIN } from './actions'

const initialState = [];

export default (state = initialState, action) => {
    switch(action.type) {
        case ADD_COIN:
            return action.portfolio;
        default:
            return state;
    }
}
5

5 Answers

84
votes

Your issue lies with how you're importing your coins reducer:

import { coins } from './coins'

The latter tries to obtain a named export returned from the file in ./coins.

You are not using any named exports only export default, therefore you just need to import the file as follows:

import coins from './coins';

Using the latter will result with the fact that coins will then contain the value of export default; which will be the coins reducer.

21
votes

Even when all your imports are correctly imported, this can still happen for one other reason. Circular Dependency!

In my case, this happeded because of a circular dependency in a file. I had two circular dependecy in the project that I created accedentally. Example: rootReducer.ts -> authSlice.ts -> rootReducer.ts.

These dependencies are often not as easy to debug. I used this package to check for circular dependencies. Once the circular dependency was removed, all was well.

6
votes

Ah just found it, I was importing my coins reducer incorrectly...

import { combineReducers } from 'redux'
import coins from './coins' // because I have coins/index.js

export default combineReducers({
    coins
});

instead of

import { coins } from './coins'
5
votes

This was my fix:

import { combineReducers } from 'redux'
import { coins } from './coins'

export default combineReducers({
    coinsState: coins || (() => null) // By adding this I resolved it.
});
0
votes

In my case, I was not adding a default property to my reducers. When I added it, it worked. here is my code;

const counterReducer = (state = 0, action) => {
    switch(action.type){
      case 'INCREMENT':
        return state + 1;
      case 'DECREMENT':
          return state - 1;
      default:
        return state;    
    }
  }
  
export default counterReducer;

and combinde file;

import   counter   from './counter';
import { combineReducers } from 'redux';

const allReducers = combineReducers({
    counter: counter,
   
});

export default allReducers;