TypeError: невозможно прочитать карту свойств undefined React Native Redux

Я попытался создать редуктор, следуя той же логике примера, который я работал с репозиториями git.

Вот сказал редуктор:

/**
 * Created by kenji on 3/9/18.
 */
/**
 * /stock?search=String
 * Searches Stock table, checking for given search value
 * and returns an array that contains that value
 * @action GET
 * @returns [array]
 * @type {string}
 */
export const GET_STOCK_LIST = 'ReduxStarter/stock_list/LOAD';
export const GET_STOCK_LIST_SUCCESS = 'ReduxStarter/stock_list/LOAD_SUCCESS';
export const GET_STOCK_LIST_FAIL = 'ReduxStarter/stock_list/LOAD_FAILURE';

/**
 * /stock/${id}
 * Gets an ID passed to it and returns an object if it exists
 * @action GET
 * @returns {object}
 * @type {string}
 */
export const GET_STOCK = 'ReduxStarter/stock/LOAD';
export const GET_STOCK_SUCCESS = 'ReduxStarter/stock/LOAD_SUCCESS';
export const GET_STOCK_FAIL = 'ReduxStarter/stock/LOAD_FAIL';

/**
 * /stock/${id}
 * Updates Stock by passing an object with new variables to update with
 * @action PUT
 * @returns {null}
 * @type {string}
 */
export const PUT_STOCK = 'ReduxStarter/stock/CHANGE';
export const PUT_STOCK_SUCCESS = 'ReduxStarter/stock/CHANGE_SUCCESS';
export const PUT_STOCK_FAIL = 'ReduxStarter/stock/CHANGE_FAIL';

/**
 * /stock/${id}/barcodes
 * Gets the barcodes of an a stock item if the ID is valid
 * @action: GET
 * @returns [array]
 * @type {string}
 */
export const GET_BARCODES = 'ReduxStarter/stock/barcodes/LOAD';
export const GET_BARCODES_SUCCESS = 'ReduxStarter/stock/barcodes/LOAD_SUCCESS';
export const GET_BARCODES_FAIL = 'ReduxStarter/stock/barcodes/LOAD_FAIL';

/**
 * /stock/barcode/${barcode}
 * Gets a stock item from the supplied barcode
 * @action: GET
 * @returns [array]
 * @type {string}
 */
export const GET_STOCK_FROM_BARCODE = 'ReduxStarter/stock/barcode/LOAD';
export const GET_STOCK_FROM_BARCODE_SUCCESS = 'ReduxStarter/stock/barcode/LOAD_SUCCESS';
export const GET_STOCK_FROM_BARCODE_FAIL = 'ReduxStarter/stock/barcode/LOAD_FAIL';

const initialState = {
    stockList: [],
    stock: {},
    result: {},
    barcodeList: [],
    stockFromBarcode: {},
};

export default function reducer(state = initialState, action) {
    switch(action.type) {
        case GET_STOCK_LIST:
            return { ...state, loadingStockList: true };
        case GET_STOCK_LIST_SUCCESS:
            return { ...state, loadingStockList: false, stockList: action.payload.data };
        case GET_STOCK_LIST_FAIL:
            return { ...state, loadingStockList: false, stockListError: 'Failed to retrieve stock list' };
        case GET_STOCK:
            return { ...state, loadingStock: true };
        case GET_STOCK_SUCCESS:
            return { ...state, loadingStock: false, stock: action.payload.data };
        case GET_STOCK_FAIL:
            return { ...state, loadingStock: false, stockError: 'Failed to retrieve stock list' };
        case PUT_STOCK:
            return { ...state, loadingStockUpdate: true };
        case PUT_STOCK_SUCCESS:
            return { ...state, loadingStockUpdate: false, result: action.payload.data };
        case PUT_STOCK_FAIL:
            return { ...state, loadingStockUpdate: false, stockUpdateError: 'Failed to update stock list' };
        case GET_BARCODES:
            return { ...state, loadingBarcodes: true };
        case GET_BARCODES_SUCCESS:
            return { ...state, loadingBarcodes: false, barcodeList: action.payload.data };
        case GET_BARCODES_FAIL:
            return { ...state, loadingBarcodes:false, barcodesError: 'Failed to load barcodes' };
        case GET_STOCK_FROM_BARCODE:
            return { ...state, loadingStockFromBarcode: true };
        case GET_STOCK_FROM_BARCODE_SUCCESS:
            return { ...state, loadingStockFromBarcode: false, stockFromBarcode: action.payload.data };
        case GET_STOCK_FROM_BARCODE_FAIL:
            return { ...state, loadingStockFromBarcode: false, stockFromBarcodeError: 'Failed to get stock item from barcode' };
        default:
            return state;
    }
}

export function listStockArray(searchQuery, pageSize = 50, pageNumber = 1) {
    return {
        type: GET_STOCK_LIST,
        payload: {
            request: {
                url: `/stock?search=${searchQuery}&pageSize=${pageSize}&pageNumber=${pageNumber}`
            }
        }
    };
}

export function listStockItem(stockID) {
    return {
        type: GET_STOCK_LIST,
        payload: {
            request: {
                url: `/stock/${stockID}`
            }
        }
    };
}

export function updateStock(stockID, data) {
    return {
        type: GET_STOCK_LIST,
        payload: {
            request: {
                url: `/stock/${stockID}`,
                method: `PUT`,
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                },
                data: data,
            }
        }
    };
}

export function listStockBarcodes(stockID) {
    return {
        type: GET_BARCODES,
        payload: {
            request: {
                url: `/stock/${stockID}/barcodes`
            }
        }
    };
}

export function listStockFromBarcode(barcode) {
    return {
        type: GET_BARCODES,
        payload: {
            request: {
                url: `/stock/barcode/${barcode}`
            }
        }
    };
}

Теперь я получаю сообщение об ошибке, указанное в заголовке: ** TypeError: не удается прочитать карту свойства undefined **

Вот внедрение редукторов в приложение:

import reducers from './redux/reducers/lots_reducer';
import StockList from './components/StockList';

const client = axios.create({
    baseURL: 'https://api.github.com',
    responseType: 'json'
});

const store = createStore(reducers, applyMiddleware(axiosMiddleware(client)));

const Stack = createStackNavigator({
    StockList: {
        screen: StockList
    },
});

export default class App extends Component {
    render() {
        return (
            <Provider store={store}>
                <View style={styles.container}>
                    <Stack/>
                </View>
            </Provider>
        );
    }
}

И, наконец, собственно компонент:

import { connect } from 'react-redux';

import { listStockArray } from '../redux/reducers/lots_reducer';

class StockList extends Component {

    componentDidMount() {
        this.props.listStockArray('panadol');
    }

    renderItem = ({ stockList }) => (
        <TouchableOpacity
            style={styles.item}
            onPress={() => this.props.navigation.navigate(`Detail`, { name: stockList.StockID })}
        >
            <Text>{stockList.TradeName}</Text>
        </TouchableOpacity>
    );

    render() {
        const { stockList } = this.props;
        return (
            <FlatList
                styles={styles.container}
                data={stockList}
                renderItem={this.renderItem}
            />
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1
    },
    item: {
        padding: 16,
        borderBottomWidth: 1,
        borderBottomColor: '#ccc'
    }
});

const mapStateToProps = state => {
    let storedRepositories = state.repos.map(repo => ({ key: (repo.id).toString(), ...repo }));
    return {
        repos: storedRepositories
    };
};

const mapDispatchToProps = {
    listStockArray
};

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

Извините за большой объем сброшенного кода, все это связано, и я считаю, что ошибка находится где-то в неопределенном начальном состоянии, но я не вижу, что я пропустил, определяя


person Cacoon    schedule 03.09.2018    source источник
comment
Я не вижу repos определенного в вашем редукторе. Для меня ошибка довольно ясна, он пытается вызвать map() что-то repos, которое не определено.   -  person Andrei Olar    schedule 03.09.2018


Ответы (3)


Этот код

const mapStateToProps = state => {
    let storedRepositories = state.repos.map(repo => ({ key: (repo.id).toString(), ...repo }));
    return {
        repos: storedRepositories
    };
};

означает, что вы хотите преобразовать (изменить свойство id на key) state.repos с помощью функции карты и вернуть как repos с помощью промежуточной переменной storedRepositories. Эти детали выглядят оригинально, без изменений по сравнению с репозиториями.

Ошибка возникает из-за того, что состояние не содержит массива repos. У вас есть несколько других массивов в состоянии (initialState в reducer), но ни один из них не repos.

В reducer вы храните полезные данные (полученные данные) в массивах хранилища, например.

    case GET_STOCK_LIST_SUCCESS:
        return { ...state, loadingStockList: false, stockList: action.payload.data };

хранит данные в stockList. Для других успешных действий у вас есть другие имена массивов.

Компонент не обязательно должен использовать все данные хранилища, вы можете использовать только те части, которые его интересуют - это причина для mapStateToProps сопоставления. Вы можете получить это так просто, как

const mapStateToProps = state => {
    return {
        stockList: state.stockList, 
        stock: state.stock
    };
};

Эти значения будут доступны как this.props.stockList и this.props.stock.

person xadm    schedule 03.09.2018
comment
Цените это, я очень новичок в redux, и это сбивало с толку, где я терялся, это имеет большой смысл :) - person Cacoon; 04.09.2018

Похоже, вы не определяете repos, как вы хотите его сопоставить?

const initialState = {
  stockList: [],
  stock: {},
  result: {},
  barcodeList: [],
  stockFromBarcode: {},
  repos: []
};

Или, альтернативно, вы имели в виду другое поле.

person sagi    schedule 03.09.2018

Потому что вы пытаетесь использовать map функцию, которая работает с массивом, но вы repo, которая не является массивом. Есть вероятность, что repo не будет, когда вы mapping (может быть до присвоения значения).

Подход. Я просто проверяю, где это массив, используя Array.isArray(), если массив, то может вернуть пустой массив.

Как упоминалось в @sagi, лучше инициализировать свое состояние с помощью поля repo как пустого массива. в основном такая ошибка возникает, когда

вы пытаетесь использовать функцию массива для элемента без массива

person Revansiddh    schedule 03.09.2018
comment
Фактически, repos не упоминается где-либо в коде, но где он использует карту. - person sagi; 03.09.2018
comment
Да, на самом деле он пытается отобразить undefined. т - person Revansiddh; 03.09.2018