簡體   English   中英

如何更新Redux狀態而不會出錯

[英]How do I update the redux state without running into errors

使用某些方法時,我需要更新Redux存儲。 我可以在掛載並調用updateCartList()時在組件中呈現虛擬數據,但是當我嘗試使用componentDidUpdate() updateCartInfo()進行更新並調用updateCartInfo()來更新購物車時,出現錯誤Cannot read property 'id' of undefined

編輯:添加了完整的組件和操作

這是虛擬數據dataList

export const dataList = [
    {
        id: '1',
        image: '/rice.jpg',
        price: 32,
        product: 'Yellow Corn',
        quantity: 2,
    },
    {
        id: '2',
        image: '/rice.jpg',
        price: 400,
        product: 'Beans',
        quantity: 5,
    },
    {
        id: '3',
        image: '/rice.jpg',
        price: 32,
        product: 'Banana',
        quantity: 1,
    },
];

成分還原劑

const initialState = {
    cart: new Map(),
};

/**
 * Creates a Javascript Map with the cart's items mapped by id
 *
 * @param {Array} cartData - a cart item
 * @return {Map} - the new cart data list
 */

function generateCartsMap(dataList) {
    const cartData = new Map();

    dataList.forEach(list => {
        const { id } = list;
        cartData.set(id, list);
    });

    return cartData;
}

/**
 * Updates the data in the cart list
 *
 * @param {Object} cartItem - the cart item to be updated
 * @param {Map} list - the list of producer products
 * @return {Map} - the updated dataSource
 */
function updateCartInfo(cartItem, list) {
    const { id } = cartItem;
    const newList = new Map([...list.entries()]);

    newList.set(id, cartItem);

    return newList;
}

export default (state = { ...initialState }, action) => {
    switch (action.type) {
        case UPDATE_CART_LIST: {
            const { payload } = action;
            return {
                ...state,
                cart: generateCartsMap(payload),
            };
        }

        case UPDATE_CART_INFO: {
            const { payload } = action;
            const { cart } = state;

            return {
                ...state,
                cart: updateCartInfo(payload, cart),
            };
        }
        default:
            return state;
    }
};

內部應用程序狀態和方法

    class Cart extends Component {
    state = {
        dataList: dataList,
    };

    componentDidMount() {
        const { updateCartList } = this.props.actions;
        const { dataList } = this.state;
        updateCartList(dataList);
    }

    componentDidUpdate(prevProp) {
        const { cart: newList } = this.props;
        const { cart: oldList } = prevProp;

        if (newList != oldList) {
            const { updateCartInfo } = this.props.actions;
            updateCartInfo();
        }
    }

    handleRemove = item => {
        const { cart } = this.props;
        const defaultCart = [...cart.values()];

        const newCart = defaultCart.filter(({ id }) => id !== item.id);
        this.setState({
            dataList: newCart,
        });
    };

    handleQuantityChange = (row, action) => {
        const { cart } = this.props;
        const values = [...cart.values()];
        const index = values.findIndex(item => row.id === item.id);
        if (action === 'add') {
            values[index] = {
                ...values[index],
                quantity: values[index].quantity + 1,
            };
        } else {
            values[index] = {
                ...values[index],
                quantity:
                    values[index].quantity > 1
                        ? values[index].quantity - 1
                        : values[index].quantity,
            };
        }
        this.setState({
            dataList: values,
        });
    };

    handleClearCart = () => {
        const cart = [];
        this.setState({
            dataList: cart,
        });
    };

    render() {
        const { cart } = this.props;
        const values = [...cart.values()];

        return (
            <div className="cart-page">
                <div className="cart-top">
                    <h2 className="cart-heading">
                        {`Cart`}
                        <Badge
                            count={values.length}
                            // title={}
                            style={{ backgroundColor: '#001529' }}
                        />
                    </h2>

                    <Popconfirm
                        className="cart-clear"
                        title="Are you sure you want to remove item?"
                        onConfirm={() => this.handleClearCart()}
                    >
                        <Button type="danger">{'Clear Cart'}</Button>
                    </Popconfirm>
                </div>

                <div className="cart-top">
                    <AppLink key={MARKET} to={MARKET}>
                        <Button className="cart-heading">{`Continue Shopping`}</Button>
                    </AppLink>
                    <AppLink key={'checkout'} to={'./'}>
                        <Button className="cart-checkout">{'Checkout'}</Button>
                    </AppLink>
                </div>

                <Table
                    className="cart-table"
                    columns={[
                        {
                            className: 'cart-table',
                            dataIndex: 'product',
                            key: 'product',
                            render: (text, record) => (
                                <div className="product-display">
                                    <img src={record.image} />
                                    <p>{record.product}</p>
                                </div>
                            ),
                            title: 'Product',
                            width: '25%',
                        },
                        {
                            className: 'cart-table',
                            dataIndex: 'price',
                            key: 'price',
                            title: 'Price',
                        },
                        {
                            className: 'cart-table',
                            dataIndex: 'quantity',
                            key: 'quantity',
                            render: (text, record) => (
                                <div className="quantity-container">
                                    <div className="quantity-value">{record.quantity}</div>
                                    <div className="quantity-actions">
                                        <Icon
                                            type="caret-up"
                                            title="Add"
                                            onClick={() => this.handleQuantityChange(record, 'add')}
                                        />
                                        <Icon
                                            type="caret-down"
                                            title="Reduce"
                                            onClick={() => this.handleQuantityChange(record, 'sub')}
                                        />
                                    </div>
                                </div>
                            ),
                            title: 'Quantity',
                        },
                        {
                            className: 'cart-table',
                            dataIndex: 'amount',
                            key: 'amount',
                            render: (text, record) => `${record.price * record.quantity}`,
                            title: 'Amount',
                        },
                        {
                            className: 'cart-table',
                            key: 'action',
                            render: (text, record) => (
                                <Popconfirm
                                    title="Are you sure you want to remove item?"
                                    onConfirm={() => this.handleRemove(record)}
                                >
                                    <a href="javascript:;" className="danger">{`Remove`}</a>
                                </Popconfirm>
                            ),
                            title: 'Action',
                        },
                    ]}
                    dataSource={values}
                    rowKey={record => record.id}
                />
            </div>
        );
    }
}

const mapStateToProps = state => ({
    cart: getCart(state),
});

const mapDispatchToProps = dispatch => ({
    actions: bindActionCreators(actions, dispatch),
});

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

actions.js

import { UPDATE_CART_INFO, UPDATE_CART_LIST } from './actionTypes';

/**
 * Triggers request to update cart items
 *
 * @function
 * @param {Object} payload An object of cart dataSource
 * @return {void} The {@link actionTypes.UPDATE_CART_LIST UPDATE_CART_LIST} action.
 */
export const updateCartList = payload => ({
    payload,
    type: UPDATE_CART_LIST,
});

/**
 * Triggers request to update cart details
 *
 * @function
 * @param {Object} payload An object of captured cart details
 * @return {void} The {@link actionTypes.UPDATE_CART_INFO UPDATE_CART_INFO} action.
 */
export const updateCartInfo = payload => ({
    payload,
    type: UPDATE_CART_INFO,
});

選擇

import { NAME } from './constants';

/**
 * Selects the <tt>user</tt> key.
 *
 * @function
 * @param {Object} state - redux store state
 * @return {Number} the state data of the signin which contains user data
 * {@link module:cart/constants::INITIAL_STATE constants::INITIAL_STATE}).
 */
export const getCart = state => state[NAME].cart;

updateCartInfo(cartItem, list)兩個參數: cartItemlist 它做的第一件事是嘗試解構cartItemcartItem獲取id屬性。

但是,這里您不帶任何參數調用該函數:

componentDidUpdate(prevProp) {
  const { cart: newList } = this.props;
  const { cart: oldList } = prevProp;

  if (newList != oldList) {
    const { updateCartInfo } = this.props.actions;
    updateCartInfo(); // <------------ HERE
  }
}

因此,有cartItemundefined而javascript無法讀取undefined的屬性id


可能的解決方法:

function updateCartInfo(cartItem, list) {
  if(cartItem && list){
    const { id } = cartItem;
    const newList = new Map([...list.entries()]);
    newList.set(id, cartItem);
    return newList;
  }
}

編輯:

嘗試這個:

componentDidUpdate(prevProp) {
  const { cart: newList } = this.props;
  const { cart: oldList } = prevProp;

  if (newList != oldList) {
    const { updateCartInfo } = this.props.actions;
    updateCartInfo(null, newList); // <------------ HERE
  }
}

和:

function updateCartInfo(cartItem, list) {
  if(cartItem && list){
    const { id } = cartItem;
    const newList = new Map([...list.entries()]);
    newList.set(id, cartItem);
    return newList;
  } else if (list) {  // <----- HERE
    return list;      // <----- HERE
  }
}

除此之外,您還可以重新考慮為什么不使用任何參數調用updateCartList()函數,並調整代碼邏輯使其更適合於此。 但是在我看來,這超出了堆棧溢出問題的范圍。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM