Leon Gaban
Leon Gaban

Reputation: 39034

React-Redux - No reducer provided for key "coins"

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;
    }
}

Upvotes: 55

Views: 41988

Answers (8)

Mikhail Batcer
Mikhail Batcer

Reputation: 2065

In the tested reducer in question, I had import of some constant from another reducer. Copy-pasting the value and removing the import fixed the warning.

(Of course it makes sense to extract it to some third file)

Upvotes: 0

bo1jan
bo1jan

Reputation: 1

i cannot get products there is my code on Admin.js enter image description here

const products = useSelector((state) => state.products.array)
console.log(products);

and when i run it i got a error Cannot read properties of undefined (reading 'array')

and there is my store.js code :

import { configureStore } from "@reduxjs/toolkit";
import productSlice from "./reducers/productSlice";

export const store = configureStore({
    reducer: {
        products: productSlice
    }
})

there is my index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import { store } from './redux/store';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <Provider store={store}>
        <App />
    </Provider>
);

there is my productSlice.js

import { createSlice } from "@reduxjs/toolkit";

const productSlice = createSlice({
    name: 'products',
    initialState: { array: [] },
    reducers: {
        setProductArr: (state, action) => {
            state.array = action.payload
        }
    }
})

export const { setProductArr } = productSlice.actions

export default productSlice.reducers

sorry this is my first time asking to stackoverflow

Upvotes: 0

twboc
twboc

Reputation: 1607

If nothing worked for you this might be a circular dependency. I had a project like that requiring store state in the slice. Instead of using the store there was a thunk available that can provide you with the state without importing the store itself. If you have this edge case you can get state from thunk.

thunkAPI.getState()

Upvotes: 1

Timur
Timur

Reputation: 1343

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;

Upvotes: 0

sasidhar
sasidhar

Reputation: 7752

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.

Upvotes: 45

gildniy
gildniy

Reputation: 3933

This was my fix:

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

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

Upvotes: 4

Pineda
Pineda

Reputation: 7593

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.

Upvotes: 94

Leon Gaban
Leon Gaban

Reputation: 39034

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'

Upvotes: 10

Related Questions