srgg6701
srgg6701

Reputation: 2048

Is it possible not to use combineReducers in react-redux app?

I have an app where combineReducers is used as it is prescribed by react-redux pack. So in my connected component I have a function

function mapStateToProps(state){

    return { 
        listedComments: // a prop name
        state.allcomments // a reducer name
    }
}

...where allcomments is the name of one of the reducers. But I have only one reducer for now, so I wonder is it possible to not use combineReducers at all, but keep using that functions?

UPDATE


I have an app where combineReducers is used as it is prescribed by react-redux pack. So in my connected component I have a function

function mapStateToProps(state){

    return { 
        listedComments: // a prop name
        state.allcomments // a reducer name
    }
}

...where allcomments is the name of one of the reducers. But I have only one reducer for now, so I wonder is it possible to not use combineReducers at all, but keep using that functions?

UPDATE


Sorry, it seems that I have provided not enough details. So, the app is structured like this:

actions
  default.js
components
  App.js
  Buttons.js
reducers
  default.js
index.js

It works perfectly with combineReducers, but doesn't without it as something is wrong in the code. Here the parts of the app (which is of course, very primitive) being responsible for the problem:

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import defaultReducer from './reducers/default'
import App from './components/App'

ReactDOM.render(
    <Provider store={createStore(defaultReducer, {})}>
        <App />
    </Provider>, 
    document.getElementById('root')
);

reducers/default.js

const defaultReducer = (state =0, action) => {

    switch (action.type) {
        case 'INCREMENT':
            return state + 1;
        case 'DECREMENT':
            return state - 1;
        default:
            return state;
    }
}
export default defaultReducer; 

App.js

import React from 'react'
import Buttons from './Buttons'
import { connect } from 'react-redux'

class App extends React.Component {

    renderCount(){
        return this.props.count;
    }

    render() {

        return (
            <React.Fragment>
                <div>Hello again!</div>
                <hr />
                Look here: {this.renderCount()}
                <hr />
                <Buttons />
            </React.Fragment>
        )
    }
}

function mapStateToProps(store) {
    return { count: store.defaultReducer }
}

export default connect(mapStateToProps)(App)

I supposed that mapStateToProps can use store, which, supposedly, is shipped by Provider. but it is an empty object.

Upvotes: 1

Views: 1502

Answers (2)

zkcro
zkcro

Reputation: 4344

It seems like you're stuck with the shape of your state, honestly the best place to start if by actually looking at that it is (e.g. by adding a console.log(state) to your mapStateToProps).

If we go back to basics, a reducer is just a function that takes a state and an action and returns a new state. This applies to all reducers, including your defaultReducer. Whatever that reducer returns is the state of your store. So in your case:

const defaultReducer = (state = 0, action) => {
  switch (action.type) {
    ...
    default: return state
  }
}

// you don't need the second parameter for createStore as you're not
// pre-populating the store with a specific non-default state. You
// can just rely on the default argument from your reducer to set the
// initial state.
const store = createStore(defaultReducer)

console.log(store.getState())
// outputs: 0

The state is just the single integer that your reducer returns. And your mapStateToProps would end up being:

const mapStateToProps = (state) => {
  return { count: state }
}

(As a side note, mapStateToProps is passed the state, not the store itself, so we usually name its argument state.)

Upvotes: 0

Big Daddy
Big Daddy

Reputation: 5224

You are misunderstanding what mapStatetoProps() is all about. This response may seem redundant, but its function is to map the App's state to the props in your component/container, just like the name implies. Reducers will update the App's state, and by using mapStatetoProps(), your components/containers can reflect this in their props. Am I misunderstanding your question?

EDIT: You don't need to use combineReducers() because you can have one reducer with everything in it as Zaid commented. Either way, you're not going to specifically reference a reducer in mapStatetoProps() and you do need to do use this function. Something like this:

function mapStateToProps(state){    
    return { 
        listedComments: state.listedComments,
        allcomments: state.allComments
    }
}

State will be pushed into mapStateToProps() with Redux's help. Make sure you're using Redux's connect to hook your components into Redux:

import { connect } from "react-redux";

EDIT 2: Your reducer isn't right. You're trying to increment state (the store) which is not possible. You need to have a property in state that you increment, like 'counter'. And remember that you should not mutate state. So, something like this:

const initialState = {
  counter: 0
};
const defaultReducer = (state = initialState, action) => {

  switch (action.type) {
      case 'INCREMENT':
      return [
        ...state,
        {
          counter: state.counter + 1
        }
      ];
      case 'DECREMENT':
      return [
        ...state,
        {
          counter: state.counter - 1
        }
      ];
      default:
          return state;
  }
}
export default defaultReducer;

Also, the createStore() looks a bit odd to me. I think it should look more like this (I may be totally wrong about this);

<Provider store={createStore(defaultReducer}>

Upvotes: 1

Related Questions