首页 > 解决方案 > redux reducer 出现 Invariant Violation 错误尝试获取 Frame for out of range index NaN Flatlist

问题描述

redux 新手,尝试构建一个简单的购物车。从教程中,我得到了 redux 的基本布局。所以我创造了其中的一些

主页.js

'use strict';

import React, { Component } from 'react';
import {
    StyleSheet,
    FlatList,
    View,
    Text,
    Button,
    ActivityIndicator
} from 'react-native';

import {bindActionCreators} from 'redux';
import { connect } from 'react-redux';

import * as Actions from '../actions'; //Import your actions

class Home extends Component {
    constructor(props) {
        super(props);

        this.state = {
        };

        this.renderItem = this.renderItem.bind(this);
    }

    componentDidMount() {
        this.props.getData(); //call our action
    }

    static navigationOptions = {
       title: "Test",
       headerStyle: {
          backgroundColor: '#4050B5',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
            fontWeight: 'bold'
        }
    };


    render() {
        if (this.props.loading) {
            return (
                <View style={styles.activityIndicatorContainer}>
                    <ActivityIndicator animating={true}/>
                </View>
            );
        } else {
            return (
                <View style={{flex:1, backgroundColor: '#F5F5F5', paddingTop:20}}>
                    <FlatList
                        ref='listRef'
                        data={this.props.data}
                        renderItem={this.renderItem}
                        keyExtractor={(item, index) => item.sno+item.name}/>

                        <Button
                         onPress={() => {this.props.navigation.navigate('Cart')}}
                         title="View Cart"
                         color="#841584"
                        />
                </View>

            );
        }
    }

    renderItem({item, index}) {
        return (
            <View style={styles.row}>
                <Text style={styles.title}>
                    {(parseInt(index) + 1)}{". "}{item.name}
                </Text>
                <Text style={styles.description}>
                    {item.ver}
                </Text>
                 <Button
                         onPress={() => {this.props.testFunc(item)}}
                         title="Add to Cart"
                         color="#4050B5"
                        />
            </View>
        )
    }
};



// The function takes data from the app current state,
// and insert/links it into the props of our component.
// This function makes Redux know that this component needs to be passed a piece of the state
function mapStateToProps(state, props) {
    return {
        loading: state.dataReducer.loading,
        data: state.dataReducer.data
    }
}

// Doing this merges our actions into the component’s props,
// while wrapping them in dispatch() so that they immediately dispatch an Action.
// Just by doing this, we will have access to the actions defined in out actions file (action/home.js)
function mapDispatchToProps(dispatch) {
    return bindActionCreators(Actions, dispatch);
}

//Connect everything
export default connect(mapStateToProps, mapDispatchToProps)(Home);

const styles = StyleSheet.create({
    activityIndicatorContainer:{
        backgroundColor: "#fff",
        alignItems: 'center',
        justifyContent: 'center',
        flex: 1,
    },

    row:{
        borderBottomWidth: 1,
        borderColor: "#ccc",
        padding: 10
    },

    title:{
        fontSize: 15,
        fontWeight: "600"
    },

    description:{
        marginTop: 5,
        fontSize: 14,
    }
});

减速器 index.js

import { combineReducers } from 'redux';

import { DATA_AVAILABLE,
         ADD_TO_CART 
        } from "../actions/" //Import the actions types constant we defined in our actions

let dataState = { data: [], loading:true };
let cartState = { data: [] };


const dataReducer = (state = dataState, action) => {
    switch (action.type) {
        case DATA_AVAILABLE:
            state = Object.assign({}, state, { data: action.data, loading:false });
            return state;
        default:
            return state;
    }
};

const cartReducer = (state = cartState, action) => {
    switch (action.type) {
        case ADD_TO_CART:
            state = Object.assign({}, state, { data: action.data});
            console.log("state data => "+state.data);
            return state;
        default:
            return state;
    }
};

// Combine all the reducers
const rootReducer = combineReducers({
    dataReducer,
    cartReducer
    // ,[ANOTHER REDUCER], [ANOTHER REDUCER] ....
})

export default rootReducer;

动作 index.js

export const DATA_AVAILABLE = 'DATA_AVAILABLE';
export const ADD_TO_CART = "ADD_TO_CART";

//Import the sample data
import Data from '../instructions.json';

export function getData(){
    return (dispatch) => {

        //Make API Call
        //For this example, I will be using the sample data in the json file
        //delay the retrieval [Sample reasons only]
        /*
        setTimeout(() => {
            const data  = Data.instructions;
            dispatch({type: DATA_AVAILABLE, data:data});
        }, 2000);
        */
        fetch('https://tetapi-cart.com?vers[]=dc')
            .then((response) => response.json())
            .then((responseJson) => {
                dispatch({type: DATA_AVAILABLE, data:responseJson.result});
            })
            .catch((error) => {
              console.error(error);
        });

    };
}

export function testFunc(user){
    return (dispatch) => {
        dispatch({type: ADD_TO_CART, data:user});
        console.log(user);
    };
}

购物车.js

'use strict';

import React, { Component } from 'react';
import {
    StyleSheet,
    FlatList,
    View,
    Text,
    Button,
    ActivityIndicator
} from 'react-native';

import {bindActionCreators} from 'redux';
import { connect } from 'react-redux';

import * as Actions from '../actions'; //Import your actions

class Cart extends Component {
    constructor(props) {
        super(props);

        this.state = {
        };

        this.renderItem = this.renderItem.bind(this);
    }

    componentDidMount() {
        //this.props.getData(); //call our action
    }

    static navigationOptions = {
       title: "Your Shopping Cart",
       headerStyle: {
          backgroundColor: '#4050B5',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
            fontWeight: 'bold'
        }
    };


    render() {
        if (this.props.data == "") {
            return (
                <View style={{flex:1, backgroundColor: '#F5F5F5', paddingTop:20}}>
                    <Text>Shopping cart is empty</Text>
                </View>
            );
        } else {
            return (
                <View style={{flex:1, backgroundColor: '#F5F5F5', paddingTop:20}}>
                    <Text>Shopping has something</Text>
                     <FlatList
                        ref='listCartRef'
                        data={this.props.data}
                        renderItem={this.renderItem}
                        keyExtractor={(item, index) => item.sno+item.name}/>
                </View>

            );
        }
    }


    renderItem({item, index}) {
        return (
            <View style={styles.row}>
                <Text style={styles.title}>
                    {(parseInt(index) + 1)}{". "}{item.name}
                </Text>
                <Text style={styles.description}>
                    {item.ver}
                </Text>
                 <Button
                         onPress={() => {this.props.testFunc(item)}}
                         title="Add to Cart"
                         color="#4050B5"
                        />
            </View>
        )
    }

};



// The function takes data from the app current state,
// and insert/links it into the props of our component.
// This function makes Redux know that this component needs to be passed a piece of the state
function mapStateToProps(state, props) {
    return {
        data: state.cartReducer.data
    }
}

// Doing this merges our actions into the component’s props,
// while wrapping them in dispatch() so that they immediately dispatch an Action.
// Just by doing this, we will have access to the actions defined in out actions file (action/home.js)
function mapDispatchToProps(dispatch) {
    return bindActionCreators(Actions, dispatch);
}

//Connect everything
export default connect(mapStateToProps, mapDispatchToProps)(Cart);

const styles = StyleSheet.create({
    activityIndicatorContainer:{
        backgroundColor: "#fff",
        alignItems: 'center',
        justifyContent: 'center',
        flex: 1,
    },

    row:{
        borderBottomWidth: 1,
        borderColor: "#ccc",
        padding: 10
    },

    title:{
        fontSize: 15,
        fontWeight: "600"
    },

    description:{
        marginTop: 5,
        fontSize: 14,
    }
});

问题出在 cart.js 上,我无法通过点击此错误来呈现平面列表

**`TaskQueue: Error with task : Invariant Violation: Invariant Violation: Tried to get frame for out of range index NaN`**

我检查了一下,我没有看到任何问题。不确定我在购物车数据上做错了什么?而且我正在尝试连接我的购物车数据,但也不知道该怎么做。

标签: javascriptreactjsreact-nativereduxreact-redux

解决方案


我发现我的数组有问题,我设法修复它,在我添加到购物车的过程中数组格式不正确,这导致了 flatlist 错误


推荐阅读