React / Redux TypeError: this.state.dryRedBottles.map не является функцией - PullRequest
0 голосов
/ 05 декабря 2018

У меня есть компонент контейнера, который извлекает данные в Rails API, но не может успешно выполнить итерацию по этим данным, не получив следующую ошибку:

TypeError: this.state.dryRedBottles.map is not a function

Это было вызвано следующим кодом;

    render() {

    let searchResults = this.state.dryRedBottles.map((bottle) =>  <SearchResults key={bottle} name={bottle}/>)

Как вы можете видеть в приведенном выше коде, я устанавливаю переменную, равную итерации для this.state.dryRedBottles, которая должна сопоставлять каждый объект бутылки с компонентом представления SearchResults.

Я также создал функцию generateSearchResults для отладки this.props и this.state.this.state.dryRedBottles по умолчанию является пустым массивом, но он обновляется и становится массивом объектов.Поскольку итераторы, такие как .map или .forEach, работают только с массивами, я попытался смягчить это на своем сервере Rails;

def create 
    @wine_bottles = WineBottle.all 

    if params[:dryRedBottles][:fetchingRedDry] == true
        @red_dry_bottles = []

        @wine_bottles.each do |bottle|
            if (bottle.w_type == 'red') & (bottle.dry == true)
                bottle = [bottle] if !bottle.is_a?(Array)
                @red_dry_bottles.push(bottle)
            end 
        end
        render json: @red_dry_bottles
    else
        nil;
    end 
end 

Я убедился, что каждый объект JSON был помещен внутрь массива, так что, по крайней мере, так.state.dryRedBottles вернет это;[[{}], [{}], [{}]].

Мой вопрос: что является причиной этой ошибки? Какие обходные пути можно использовать для успешного использованияsearchResults?

Ниже мой контейнерный компонент во всей полноте;

class Red extends Component {

    constructor(props) {
        super(props);

        this.state = {
            // helps monitor toggling
            redDryClick: false,
            redBothClick: false,
            redSweetClick: false,
            fetchingRedDry: false,
            fetchingRedSweet: false,

            dryRedBottles: []
        };
    };

    handleSweetRequest = (event) => {
        event.preventDefault();

        this.setState(prevState => ({
            redDryClick: !prevState.redDryClick,
            redBothClick: !prevState.redBothClick
          }));
    }

    handleDryRequest = (event) => {
        event.preventDefault();
        this.setState(prevState => ({
            redSweetClick: !prevState.redSweetClick,
            redBothClick: !prevState.redBothClick,
            fetchingRedDry: !prevState.fetchingRedDry
        }));
    }

    componentDidUpdate(){
        if (this.state.fetchingRedDry === true) {
            let redDryState = Object.assign({}, this.state);
            this.props.fetchDryReds(redDryState);

            // this.props.dryRedBottles.length > this.state.dryRedBottles.length

            if (this.props.dryRedBottles !== this.state.dryRedBottles ) {
                this.setState({ dryRedBottles: this.props.dryRedBottles });
            }
        }
        debugger;
    }

    handleBothRequest = (event) => {
        event.preventDefault();

        this.setState(prevState => ({
            redDryClick: !prevState.redDryClick,
            redSweetClick: !prevState.redSweetClick
        }));
    }

    generateSearchResults = () => {
        debugger;
        if ( Array.isArray(this.props.dryRedBottles) ) {
            this.props.dryRedBottles.map((bottle) => {
                debugger;
                return bottle;
            })
        }
    }

    render() {

        let searchResults = this.state.dryRedBottles.map((bottle) =>  <SearchResults key={bottle} name={bottle}/>)

        return (
            <div>
                <h2>Welcome to... Red</h2>

                <FormControlLabel
                    control={
                    <Switch
                        // configuring @material-ui Switch componanet
                        value="hidden"
                        color="primary"
                        id="redSweet"
                        disableRipple

                        // handles previous State + redux + API call
                        onChange={this.handleSweetRequest}
                        disabled={this.state.redSweetClick}
                    />
                    }
                    label="Sweet"
                />


                <FormControlLabel
                    control={
                    <Switch
                        // configuring @material-ui Switch componanet
                        // value="hidden"
                        value="RedDry"
                        color="primary"
                        id="redDry"
                        disableRipple

                        // handles previous State + redux + API call
                        onChange={(event) => this.handleDryRequest(event)}
                        disabled={this.state.redDryClick}
                    />
                    }
                    label="Dry"
                />


                <FormControlLabel
                    control={
                    <Switch
                        // configuring @material-ui Switch componanet
                        value="hidden"
                        color="primary"
                        id="redBoth"
                        disableRipple

                        // handles previous State + redux + API call
                        onChange={this.handleBothRequest}
                        disabled={this.state.redBothClick}
                    />
                    }
                    label="Both"
                />

                <div>
                    {searchResults}
                </div>
            </div>
        )
    }
}

function mapStateToProps(state) {
    return {
        dryRedBottles: state.redWineReducer
    };
}

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        fetchDryReds: fetchDryReds
    }, dispatch)
}

export default connect(mapStateToProps, mapDispatchToProps)(Red);

Ниже мой actionCreator;

    export function fetchDryReds(redDryState) {
  return (dispatch) => {
    // debugger;
    // dispatch({ type: 'LOADING_DRY_REDS' });
    return fetch('http://localhost:3001/wine_bottles', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'},
      body: JSON.stringify({dryRedBottles: redDryState})})
      .then(response => response.json())
      .then(dryRedBottles => {
        dispatch({ type: 'FETCH_DRY_REDS', dryRedBottles })});
  }
}

Ниже мой редуктор;

    export default function redWineReducer (state={}, action) {
switch (action.type) {
    case 'FETCH_DRY_REDS':
        // debugger;
        return action.dryRedBottles
    default: 
        return state;
}

}

Это массив объектов, которые я пытаюсь перебрать;

1 Ответ

0 голосов
/ 05 декабря 2018

начальное состояние - это объект ... не массив, поэтому:

export default function redWineReducer (state={}, action) {

измените его на:

export default function redWineReducer (state=[], action) {
...