减速器未接收到从动作发送的数据

时间:2019-01-03 12:39:56

标签: javascript reactjs redux

我在我的React应用程序中使用redux。我试图从我的减速器中获取数据,但是当我试图这样做时。我遇到一些错误。

  

未捕获的错误:减速器已采取行动“ RECEIVE_CATEGORY_NAME”   “ categoriesReducer”返回未定义。要忽略某个动作,您必须   明确返回先前的状态。如果您希望该减速器固定   没有值,您可以返回null而不是未定义。

在influencersNameReducer的情况下,编写的逻辑工作正常,但显示类别Reducer错误 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 :(得分:0)

您需要将减速器修改为:

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类型没有执行任何操作,因此返回undefined。所以你得到了错误。使用开关盒是实现此目的的方法。