Aniruddh Agarwal
Aniruddh Agarwal

Reputation: 917

The data sent from action is not received by reducer

I am using redux with my react application. I am trying to get the data from my reducer but when I am trying to do this. I am getting some error.

Uncaught Error: Given action "RECEIVE_CATEGORY_NAME", reducer "categoriesReducer" returned undefined. To ignore an action, you must explicitly return the previous state. If you want this reducer to hold no value, you can return null instead of undefined.

the logic written is working fine in case of influencersNameReducer but is showing an error for categoriesReducer home_reducer.js

import { RECEIVE_INFLUENCERS_NAME, RECEIVE_CATEGORY_NAME } from './home_actions';

export const influencersNameReducer = (state = [], { type, influencers }) => {
  console.log(influencers)
  return type === RECEIVE_INFLUENCERS_NAME ? influencers : state
}


export const categoriesReducer = (state = [], { type, category }) => {
  console.log(type, category)
  return type === RECEIVE_CATEGORY_NAME ? category : state
}

home_actions.js

export const RECEIVE_INFLUENCERS_NAME = 'RECEIVE_INFLUENCERS_NAME'
export const RECEIVE_CATEGORY_NAME = 'RECEIVE_CATEGORY_NAME';

const receiveInfluencersName = influencers => ({ type: RECEIVE_INFLUENCERS_NAME, influencers })

const receiveCategoryName = categories => ({ type: RECEIVE_CATEGORY_NAME, categories })

export const fetchInfluencers = _ => dispatch => {
  $.ajax({
    method: 'get',
    url: 'vip_api/influencers',
    data: { name: _ },
    success(influencers) {
      dispatch(receiveInfluencersName(influencers))
    },
    error({ responseJSON, statusText }) {
      dispatch(receiveServerErrors(responseJSON || [statusText]))
    }
  })
}

export const fetchCategories = _ => dispatch => {
  $.ajax({
    method: 'get',
    url: 'vip_api/categories',
    data: { name: _ },
    success(categories) {
      dispatch(receiveCategoryName(categories))
    },
    error({ responseJSON, statusText }) {
      dispatch(receiveServerErrors(responseJSON || [statusText]))
    }
  })
}

store.js

import {influencersNameReducer, categoriesReducer} from './Vvip/Home/home_reducer';
import { composeWithDevTools } from 'redux-devtools-extension';

const reducer = combineReducers({
categoriesReducer,
  influencersNameReducer,
})

const composeEnhancers = composeWithDevTools({
  // Specify name here, actionsBlacklist, actionsCreators and other options if needed
});
export default (state = {}) => (
  createStore(reducer, state, composeEnhancers(applyMiddleware(errorMiddleware, timeoutMiddleware, thunk)))
)

index.js

import React, { Component } from 'react'
import Select, { components } from 'react-select'
import DateRange from '../../shared/_date_range';
import moment from 'moment';
import {ethnicities, ageRanges, isoCountries} from '../../constants';
import { connect } from 'react-redux';
import {fetchInfluencers, fetchCategories} from './home_actions';

class InfluencersForm extends Component {

    constructor() {
        super();
        this.state = {
            demography: null,
            dates : {
                startDate: moment(),
                endDate: moment()
            },
            influencersName: [],
        }
    }

    handleInfluencerName = event => {
        this.props.dispatch(fetchInfluencers(event))
    }

    handleSelectedInfluencer = event => {
        console.log(event)
        this.setState({
            isMenuOpenInfluencer : false
        })
    }
    componentWillReceiveProps(newProps) {
        console.log(newProps);
        if (newProps.influencersNameReducer && newProps.influencersNameReducer.length) {
            this.setState({
                influencersName: newProps.influencersNameReducer.map((influencer, index) => {
                    return ({ value: influencer, label: influencer })
                }),
            })
        }
    }

    handleInfluencerType = event => {
        console.log(event)
    }

    handleInfluencerCountry = event => {
        console.log(event)
    }

    handleInfluencerSubscribers = event => {
        console.log(event)
    }

    handleInfluencerVideosCreated = event => {
        console.log(event)
    }

    handleInfluencerCategory = event => {
        console.log(event)
        this.props.dispatch(fetchCategories(event))
    }

    onDemographyChange = event => {
        console.log(event.currentTarget.value)
        this.setState({
            demography: event.currentTarget.value
        })
    }

    handleInfluencerAge = event => {
        console.log(event)
    }

    handleInfluencerGender = event => {
        console.log(event)
    }

    handleInfluencerEthnicity = event => {
        console.log(event)
    }

    updateDates = event => {
        console.log(event)
        this.setState({
            dates: event
        })
    }
    render() {
        const influencersType = [
            { value: 'a', label: 'Type A' },
            { value: 'b', label: 'Type B' },
            { value: 'c', label: 'Type C' }
        ]

        const influencersCategory = [
            { value: 'a', label: 'Type A' },
            { value: 'b', label: 'Type B' },
            { value: 'c', label: 'Type C' }
        ]

        const influencersAge = ageRanges.map(age => ({ value: age, label: age }))

        const influencersGender = [
            { value: 'male', label: 'Male' },
            { value: 'female', label: 'Female' }
        ]

        const influencersKeywords = [
            { value: 'youtuber', label: 'Youtuber' },
            { value: 'vlogger', label: 'Vlogger' }
        ]

        const influencersCountry = Object.keys(isoCountries).map(code => ({ value: code, label: isoCountries[code] }))

        const DropdownIndicator = (props) => {
            return components.DropdownIndicator && (
                <components.DropdownIndicator {...props}>
                    <i className="fa fa-search" aria-hidden="true" style={{ position: 'initial', color: 'black' }}></i>
                </components.DropdownIndicator>
            );
        };
        return (
            <div className='home-forms influencer-form'>
                <div className='display-flex'>
                    <Select
                        options={this.state.influencersName}
                        onChange={this.handleSelectedInfluencer}
                        closeMenuOnSelect = {true}
                        isSearchable={true}
                        components={{ DropdownIndicator }}
                        onInputChange = {this.handleInfluencerName}
                        placeholder={'Start Typing Influencers Name'}
                        classNamePrefix="vyrill"
                        className="influencers influencers-icon-name" />

                    <Select
                        options={influencersType}
                        onChange={this.handleInfluencerType}
                        placeholder='Type of Influencers'
                        classNamePrefix="vyrill"
                        className="influencers influencers-icon-type" />

                    <Select
                        options={influencersCountry}
                        onChange={this.handleInfluencerCountry}
                        isSearchable={true}
                        components={{ DropdownIndicator }}
                        placeholder='Start Typing Country'
                        classNamePrefix="vyrill"
                        className="influencers influencers-icon-country" />
                </div>
                <div className='display-flex' style={{ marginTop: 32 }}>
                    <Select
                        options={influencersType}
                        onChange={this.handleInfluencerSubscribers}
                        placeholder='Number of Subscribers'
                        classNamePrefix="vyrill"
                        className="influencers influencers-icon-type" />

                    <Select
                        options={influencersType}
                        onChange={this.handleInfluencerVideosCreated}
                        placeholder='Number of Videos Created'
                        classNamePrefix="vyrill"
                        className="influencers influencers-icon-videos-created" />

                    <Select
                        options={influencersCategory}
                        onChange={this.handleInfluencerCategory}
                        onInputChange = {this.handleInfluencerCategory}
                        isSearchable={true}
                        components={{ DropdownIndicator }}
                        placeholder='Start Typing Category'
                        classNamePrefix="vyrill"
                        className="influencers influencers-icon-country influencers-icon-category" />  {/* remove influencers-icon-country later */}
                </div>
                <div style={{ marginTop: 50 }}>
                    <div className="display-flex">
                        <div className="icon-subscribers" style={{ marginTop: 4 }}></div>
                        <div style={{ fontWeight: 700, marginTop: 4 }}>Demographics</div>
                        <div className="radio-container">
                            <label>
                                <div style={{ fontSize: 14, marginTop: 4 }}>By influencers</div>
                                <input
                                    type="radio"
                                    name="demographics"
                                    value="influencers"
                                    checked={this.state.demography === 'influencers'}
                                    onChange={this.onDemographyChange} />
                                <span className="custom-radio">
                                </span>
                            </label>
                        </div>
                        <div className="radio-container">
                            <label>
                                <div style={{ fontSize: 14, marginTop: 4 }}>By people in videos</div>
                                <input
                                    type="radio"
                                    name="demographics"
                                    value="people in videos"
                                    checked={this.state.demography === 'people in videos'}
                                    onChange={this.onDemographyChange} />
                                <span className="custom-radio"></span>
                            </label>
                        </div>
                    </div>
                </div>
                <div className="display-flex" style={{ marginTop: 40 }}>
                    <Select
                        options={influencersAge}
                        onChange={this.handleInfluencerAge}
                        placeholder='Age'
                        classNamePrefix="vyrill"
                        className="influencers" />
                    <Select
                        options={influencersGender}
                        onChange={this.handleInfluencerGender}
                        placeholder='Gender'
                        classNamePrefix="vyrill"
                        className="influencers" />
                    <Select
                        options={ethnicities}
                        onChange={this.handleInfluencerEthnicity}
                        placeholder='Ethnicity'
                        classNamePrefix="vyrill"
                        className="influencers" />
                </div>
                <div style={{marginTop: 50}}>
                    <div style={{display: 'inline'}}>Contains keywords (in transcript):</div>
                    <span className="icon-info"></span>
                    <Select
                        options={influencersKeywords}
                        onChange={this.handleInfluencerName}
                        isSearchable={true}
                        classNamePrefix="vyrill"
                        placeholder= {" "}
                        className="influencers influencers-keywords"
                        styles = {{marginTop: 10}}/>
                </div>
                <div style={{marginTop: 50}} className="date-picker">
                    <div>Posted content time range</div>
                    <DateRange dates={ this.state.dates } updateDates={ this.updateDates }/>
                    <div className="icon-arrow-right"></div>
                </div>
            </div>
        )
    }
}

const mapStateToProps = ({ influencersNameReducer, categoriesReducer }) => ({
    influencersNameReducer,
    categoriesReducer
  })

export default connect(mapStateToProps)(InfluencersForm)

Upvotes: 0

Views: 263

Answers (1)

Shubham Jain
Shubham Jain

Reputation: 930

You need to modify your reducer as:

export const influencersNameReducer = (state = [], { type, influencers }) => {
    switch(type) {
        case RECEIVE_INFLUENCERS_NAME:
            return influencers;
        default: 
            return state;
    }
}
export const categoriesReducer = (state = [], { type, category }) => {
  switch(type) {
        case RECEIVE_CATEGORY_NAME:
            return category;
        default: 
            return state;
    }
}

On every action the dispatcher goes to every reducer. Since in your code the influencersNameReducer reducer was not doing anything for type RECEIVE_CATEGORY_NAME thus returning undefined. So you were getting the error. Using switch case is the way to do this.

Upvotes: 1

Related Questions