user3846586
user3846586

Reputation: 43

Redux combineReducers Uncaught Type error: Cannot convert undefined or null to object

I beginer to react and redux and I have used combineReducers and getting

Uncaught TypeError: Cannot convert undefined or null to object.

Without the combineReducer it is working fine. Below is snippet of my Reducers.

reducers\article.js:

import { ADD_ARTICLE } from "../actiontypes/action-types";

const initialState = {
articles: []
};

const articleReducer = (state = initialState, action) => {

switch (action.type){
case ADD_ARTICLE:
return {...state, articles: [...state.articles, action.payload] };
default:
return state;
}
};

export default articleReducer;

reducers\index.js

import { combineReducers } from "redux";
import articleReducer from "./article";

export default combineReducers({
articles : articleReducer
});

actions\index.js

import {ADD_ARTICLE} from "../actiontypes/action-types";

export const addArticle = article => ({type: ADD_ARTICLE, payload: article});

store/index.js

import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers';

const initialArticlesState = {
    articles: [{"title":"some title", "id":"04503"}]
};

const middleware = [thunk];
const store = createStore(
    rootReducer,
    initialArticlesState,
    compose(
        applyMiddleware(...middleware),
        window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()  
    )

);

export default store;

components\form.js

import React, { Component } from "react";
import { connect } from "react-redux";
import uuidv1 from "uuid";
import { addArticle } from "../js/actions/index";

class ConnectedForm extends Component {
    constructor(){
        super();
        this.state = {
            title: ""
        };

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleSubmit(event) {

        event.preventDefault();
        const { title } = this.state;
        const id = uuidv1();
        console.log("submit",{ title, id });
        this.props.addArticle();
        this.setState({ title: "" });
    }

    handleChange(event) {
        this.setState({ [event.target.id]: event.target.value});
    }

    render() {
        const { title } = this.state;
        return (
            <form onSubmit={this.handleSubmit}>
                <div className="form-group">
                <label htmlFor="title">Title</label>
                <input
                    type="text"
                    className="form-control"
                    id="title"
                    value={title}
                    onChange={this.handleChange}
                />
                </div>
                <button type="submit" className="btn btn-success btn-lg">
                SAVE
                </button>
            </form>
        );
    }
}

const mapDispatchToProps = dispatch => {
    return {
        addArticle: article => dispatch(addArticle(article))
    };
};

const Form = connect(null, mapDispatchToProps)(ConnectedForm);

export default Form;

Upvotes: 1

Views: 2109

Answers (1)

devserkan
devserkan

Reputation: 17608

First change your initialArticleState like this:

const initialArticlesState = [
    { title: "some title", id: "04503" },
];

Probably you want the state as an array of objects. Those objects are articles right? So, when you set up you initial state like that you are exposing an articles state thanks to combineReducers. Your top redux state now includes an articles array which has article objects.

Then, change your reducer return statement like that:

return [ ...state, action.payload ];

Now, if you want some other things other than articles in your articles state, you can change your state shape of course. For example:

const initialArticlesState = {
    articles: [
        { title: "some title", id: "04503" },
    ],
    totalArticleNumber: 1,
};

If you do so, then you will have an articles state, which includes articles and totalArticleNumber. In this case maybe you want to change the state name maybe.

Reducer would be something like that:

return { ...state, articles: [ ...state.articles, action.payload ] };

Upvotes: 1

Related Questions