Данные, отправленные с действия, не получены редуктором - PullRequest
0 голосов
/ 03 января 2019

Я использую Redux с моим приложением реакции.Я пытаюсь получить данные от моего редуктора, но когда я пытаюсь это сделать.Я получаю сообщение об ошибке.

Uncaught Error: Дано действие «RECEIVE_CATEGORY_NAME», редуктор «categoryReducer» возвратил неопределенное.Чтобы игнорировать действие, вы должны явно вернуть предыдущее состояние.Если вы хотите, чтобы этот редуктор не содержал никакого значения, вы можете вернуть null вместо undefined.

написанная логика работает нормально в случае influenrsNameReducer, но показывает ошибку для 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)

1 Ответ

0 голосов
/ 03 января 2019

Вам нужно изменить свой редуктор как:

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

При каждом действии диспетчер идет к каждому редуктору. Поскольку в вашем коде редуктор influencersNameReducer ничего не делал для типа RECEIVE_CATEGORY_NAME, возвращая неопределенное значение. Итак, вы получили ошибку. Это можно сделать с помощью переключателя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...