【问题标题】:React/Redux TypeError: this.state.dryRedBottles.map is not a functionReact/Redux TypeError: this.state.dryRedBottles.map 不是函数
【发布时间】:2018-12-05 16:49:52
【问题描述】:

我有一个容器组件,它可以将数据提取到 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 对象都被推送到一个数组中,所以至少 this.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;
}

}

This is the array of objects I am attempting to iterate over;

【问题讨论】:

    标签: javascript ruby-on-rails reactjs react-redux redux-thunk


    【解决方案1】:

    初始状态是一个对象...不是数组所以:

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

    改成:

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

    【讨论】:

    • state 是一个对象,但dryRedBottlesstate 中的一个数组。
    • 这是从属性设置状态:this.setState({ dryRedBottles: this.props.dryRedBottles }); ...并且该属性将是一个对象...这是您的减速器的初始状态
    • 在我的减速器中,我更新了状态,所以默认情况下它是一个空数组,但现在我收到以下错误; Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead. 如果将状态设置为数组应该解决迭代它,为什么错误指出我正在迭代一个对象?
    • 在你的reducer中默认你是return state;所以一开始你正在返回初始状态......那是一个对象......你不能映射一个对象
    • 我的意思是,在我的减速器中,我将状态从state={} 更改为state=[]。当我刷新页面时,收到错误Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead.
    猜你喜欢
    • 2020-08-18
    • 2021-10-11
    • 2021-07-11
    • 2018-07-25
    • 1970-01-01
    • 2020-06-04
    • 2021-10-19
    • 2018-10-22
    • 1970-01-01
    相关资源
    最近更新 更多