【问题标题】:ReactJS - updating state array causes undefined in a different componentReactJS - 更新状态数组导致不同组件中未定义
【发布时间】:2020-01-15 04:51:27
【问题描述】:

我有一个相当复杂的 React 应用程序。我有一个带有表单和提交按钮的模式。该表单附加了一个提交处理程序,该处理程序运行一些代码。该代码的一部分是使用表单中的新数据更新订单状态数组。发生这种情况时,页面会因使用订单状态数组的不同组件而出错,该组件声明它是undefined。我不确定我是否错误地更新了状态,或者我的应用程序中是否有其他问题。我将订单和 setOrders 作为道具传递给各个组件。

这是试图更新状态数组的模态组件。 SetOrders 作为道具传递:

import ReactModal from 'react-modal';
import React, { useReducer } from 'react';
import CloseButton from './CloseButton';
import PropTypes from 'prop-types';
import { Scrollbars } from 'react-custom-scrollbars';
import { RadioGroup, Radio } from 'react-radio-group';

const initialState = {
    bagID: '',
    lineTechName: '',
    infoCorrect: '',
    materialCorrect: '',
    unwantedMaterials: '',
    unwantedMaterial: '',
    qualityAcceptable: '',
    program: 'Windows',
    sealingProperly: '',
    temperature: ''
};

const PackagerModal = (props) => {
    const {
        openPackager,
        activeOrder,
        setOrders,
        setOpenPackager,
        customStyles,
        setPackagerChecklistResults
    } = props;

    const [userInput, setUserInput] = useReducer(
        (state, newState) => ({ ...state, ...newState }),
        initialState
    );

    const handleTextChange = (evt) => {
        const { name, value } = evt.target;
        setUserInput({ [name]: value });
    };

    const handleRadioChange = (val, name) => {
        setUserInput({ [name]: val });
    };

    const handleSubmit = (evt) => {
        evt.preventDefault();

        // do database stuff
        // save to state for now
        // save form data to the packager checklist results state variable
        setPackagerChecklistResults(userInput);

        // create a new temp order so we don't mutate state and set the
        // packagerChecked field to true for this order
        const tempActiveOrder = JSON.parse(JSON.stringify(activeOrder));
        tempActiveOrder.packagerChecked = true;
        tempActiveOrder.packagerChecklist = userInput;
        console.log(tempActiveOrder);
        setOrders((prevOrders) => {
            prevOrders.map((order) => {
                return order.id === tempActiveOrder.id
                    ? tempActiveOrder
                    : order;
            });
        });

        // clear out form inputs
        setUserInput(initialState);

        // close package modal
        setOpenPackager(false);
    };

    return (
        <ReactModal
            isOpen={openPackager}
            style={customStyles}
            className={'order-details-modal'}
            closeTimeoutMS={1000}
        >
            <CloseButton setOpenModal={setOpenPackager} />
            <h2>Packager Order Checklist</h2>
            <Scrollbars autoHeight autoHeightMin={500} autoHeightMax={600}>
                <form className={'form'} onSubmit={handleSubmit}>
                    <!-- rest of the form inputs here are irrelavant -->
                    <input
                        className={'btn btn-primary d-block mx-auto mb-2'}
                        type={'submit'}
                        value={'Submit'}
                    />
                </form>
            </Scrollbars>
        </ReactModal>
    );
};

PackagerModal.propTypes = {
    openPackager: PropTypes.bool,
    setOpenPackager: PropTypes.func,
    customStyles: PropTypes.object,
    activeOrder: PropTypes.object,
    setPackagerChecklistResults: PropTypes.func
};

export default PackagerModal;

这是依赖订单状态数组在页面上显示订单的组件。订单作为道具传递:

import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { Droppable } from 'react-beautiful-dnd';
import styled from 'styled-components';
import Order from '../order/Order';
import { Scrollbars } from 'react-custom-scrollbars';
//import { ScheduleContext } from '../../schedule-context';
import '../../App.scss';

// border-right-width set below to fix an issue with doubled borders between columns
const MyOrder = styled.div`
    transition: background-color 0.5s ease;
    background-color: ${(props) =>
        props.isDraggingOver ? '#fffbc9' : '#ffffff'};
    border-style: ${(props) =>
        props.isDraggingOver ? 'dashed' : 'solid'};
    border-right-width: ${(props) =>
        props.isDraggingOver ? '3px' : '0'};
`;
const OrderColumn = (props) => {
    const {
        columnId,
        line,
        setOpenLineModal,
        setLineModalHeader,
        orders
    } = props;
    //const orders = useContext(ScheduleContext).orders;
    console.log('orderCol orders: ', orders);
    const orderIDs = props.orderIDs;

    const openLineModal = () => {
        if ((line === 'middle' || line === 'last') && orderIDs.length) {
            setLineModalHeader(props.title + ' Orders');
            setOpenLineModal(true);
        }
    };

    return (
        <Droppable droppableId={columnId}>
            {(provided, snapshot) => {
                return (
                    <MyOrder
                        className={'col order-column ' + props.line}
                        ref={provided.innerRef}
                        {...provided.droppableProps}
                        isDraggingOver={snapshot.isDraggingOver}
                        key={columnId}
                    >
                        <Scrollbars
                            // This will activate auto hide
                            autoHide
                            // Hide delay in ms
                            autoHideTimeout={1000}
                            // Duration for hide animation in ms.
                            autoHideDuration={200}
                        >
                            <h3
                                className={
                                    (line === 'middle' || line === 'last') &&
                                    orderIDs.length
                                        ? 'text-center title hand-cursor'
                                        : 'text-center title'
                                }
                                onClick={() => openLineModal()}
                            >
                                {props.title} <span>({orderIDs.length})</span>
                            </h3>
                            <div className={'orders'}>
                                {orderIDs &&
                                    orderIDs.map((orderID, index) => {
                                        const order = orders.find(
                                            (o) => o.id === orderID
                                        );

                                        return (
                                            <Order
                                                key={orderID}
                                                order={order}
                                                index={index}
                                            />
                                        );
                                    })}
                            </div>
                        </Scrollbars>
                        {provided.placeholder}
                    </MyOrder>
                );
            }}
        </Droppable>
    );
};

OrderColumn.propTypes = {
    orders: PropTypes.array,
    orderIDs: PropTypes.array,
    columnId: PropTypes.string.isRequired,
    line: PropTypes.string.isRequired,
    title: PropTypes.string.isRequired,
    setOpenLineModal: PropTypes.func.isRequired,
    setLineModalHeader: PropTypes.func.isRequired
};

export default OrderColumn;

【问题讨论】:

    标签: reactjs state


    【解决方案1】:

    您只是忘记在 setOrders 函数中返回新的映射数组:

    setOrders((prevOrders) => {
                // return this map
                return prevOrders.map((order) => {
                    return order.id === tempActiveOrder.id
                        ? tempActiveOrder
                        : order;
                });
            });
    

    另外,顺便说一句,我会创建一个这样的新数组:const newArr = [...oldArr] 而不是使用JSON.parseJSON.stringify,因为 JSON 字符串化和解析更昂贵,而且我认为它看起来更干净,但个人喜好就是这样。

    或者,对于一个对象:

    const newObj = { ...oldObj }
    

    【讨论】:

    • 我试过这个:const tempActiveOrder = [...activeOrder]; 并得到这个:TypeError: activeOrder is not iterable
    • 哦,我没有意识到它是一个对象。我更新了我的答案
    • 就是这样!这么简单的错误,但我在那个错误上花了太长时间!谢谢!
    猜你喜欢
    • 1970-01-01
    • 2022-10-15
    • 1970-01-01
    • 2017-11-05
    • 2021-09-20
    • 1970-01-01
    • 2021-06-08
    • 2021-08-29
    • 1970-01-01
    相关资源
    最近更新 更多