Formik的值不随状态更新

40
这是我使用Formik和react-bootstrap编写表格的模板。我发现一个非常奇怪的错误:如果我在构造函数中使用虚拟数据初始化我的状态,则可以正常工作;但是如果我在componentDidMount中调用setState并使用完全相同的数据来模拟API调用,则会出现严重错误。
具体来说,我发现状态变量alertVehicles数组可能具有非零长度,但相应的Formik values.alertVehicles变量可能为空。目前,编写的表单不呈现复选框。如果我在守卫子句中使用alertVehicles而不是values.alertVehicles,则会出现错误“无法读取未定义的属性‘selected’”。
import React, {Component} from 'react';
import Form from 'react-bootstrap/Form';
import { Formik } from 'formik';
import Button from 'react-bootstrap/Button';


class Alerts extends Component {
    constructor(props) {
        super(props);
        this.loadAlertData = this.loadAlertData.bind(this);
        this.state = {
            alertRecipient: {},
            alertId: '',
            alertVehicles: []
        }
    }

    componentDidMount(){
        this.loadAlertData();
    }

    loadAlertData(){
        // this will be an API call eventually, obviously.
        // if this is initialised in the constructor then everything works!
        this.setState( {
            alertRecipient: {
                name: 'Rob',
                simNumber: '0123456789',
            },
            alertId: 1,
            alertVehicles: [
                {id: 1, vrn: 'vehicle A', selected: true },
                {id: 2, vrn: 'vehicle B', selected: false },
                {id: 3, vrn: 'vehicle C', selected: true }
            ]
        })
    }

    render() {
        const { alertRecipient, alertId, alertVehicles } = this.state;
        return (
            <>
                <Formik
                    initialValues={{ alertRecipient, alertId, alertVehicles }}
                    onSubmit={ values => {
                            window.alert(JSON.stringify(values))
                        }
                    }
                    render={({values, handleChange, handleSubmit}) => (
                        <Form onSubmit={handleSubmit}>
                            <Form.Label>Name</Form.Label>
                            <Form.Control
                                type="text"
                                name="alertRecipient.name"
                                value={values.alertRecipient.name}
                                onChange={handleChange}
                            />
                            <Form.Label>Phone number</Form.Label>
                            <Form.Control
                                type="text"
                                name="alertRecipient.simNumber"
                                value={values.alertRecipient.simNumber}
                                onChange={handleChange}
                            >
                            </Form.Control>
                            <Form.Label>Vehicles</Form.Label>
                            {
                                //get an error if we just use alertVehicles.length here??
                                values.alertVehicles.length === 0 ? null : alertVehicles.map((veh, index) => (

                                    <Form.Check type="checkbox"
                                                key={veh.id}
                                                label={veh.vrn}
                                                name={`alertVehicles[${index}].selected`}
                                                checked={values.alertVehicles[index].selected}
                                                onChange={ handleChange }
                                    />
                                ))
                            }
                            <Button type="submit">Save</Button>
                        </Form>
                    )
                    }
                />
            </>
        )
    }

}

export default Alerts;

我不理解

  1. 为什么当我在构造函数中设置虚拟数据时代码可以正常运行,但在componentDidMount中却不行。
  2. 为什么values.alertVehicles似乎与alertVehicles不同步。

感谢您提前的帮助。

3个回答

79

15
这种默认行为非常不必要且浪费时间。 - Aderemi Dayo
@AderemiDayo,你有默认行为的参考资料吗?因为在Formik中,只有在enableReinitialize=true之后才能正常工作。 - Mohd Qasim
天啊,我在这个属性上浪费了多少时间.. 谢谢你。 - Maximiliano Poggio

2

其实这很有道理。大多数情况下,您不希望因为状态改变而覆盖用户在表单上可能正在进行的操作。实际上,如果用户还没有触摸任何内容,您可能会想要这样做,但之后就不需要了。

无论哪种方式,它们都会给您一个标志来控制它...


0

我遇到了同样的问题。值需要是字符串,它不接受数字,请尝试将其转换为字符串或使用模板字符串 ``。


你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community
这并没有回答问题。一旦您拥有足够的声望,您就可以评论任何帖子;相反,提供不需要询问者澄清的答案。- 来自审核 - Vojin Purić

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接