使用reactjs计算多个表单的2个日期之间的时间



我有一个应用程序,每个用户都可以以动态形式为多个用户设置时间。
单击Add field button,用户可以添加一个时间范围,时间选择器的右侧将显示这两个时间的差值。此外,我有一个默认时间:12:08 - 12:10,所以默认范围应该是0 hours and 2minutes,但这个值只是为第一次输入保存的,但当我单击Add field按钮时,我看不到计算的范围。

const Demo = () => {
const [date, setDate] = useState({ 0: "12:08" });
const [fullDate2, setFullDate2] = useState({ 0: "12:10" });
console.log(date, fullDate2);
const onFinish = values => {
console.log("Received values of form:", values, date);
};
const changeDate1 = (momentDate, dateString, key) => {
console.log(dateString, key);
setDate({ ...date, [key + 1]: dateString });
};
const changeDate2 = (momentDate, dateString, key) => {
setFullDate2({ ...fullDate2, [key + 1]: dateString });
};
const myDiff = (startSubEventTimes, endSubEventTimes, k) => {
if (Object.keys(endSubEventTimes).length) {
const startTime = moment(startSubEventTimes[k], "HH:mm");
const endTime = moment(endSubEventTimes[k], "HH:mm");
const duration = moment.duration(endTime.diff(startTime));
const hours = parseInt(duration.asHours(), 0);
const minutes = parseInt(duration.asMinutes(), 0) - hours * 60;
if (!isNaN(hours) && !isNaN(minutes)) {
return `${hours}hours and  ${minutes}minutes`;
}
}
};
return (
<Form name="dynamic_form_nest_item" onFinish={onFinish} autoComplete="off">
<Form.List name="users">
{(fields, { add, remove }) => {
return (
<div>
{fields.map(field => (
<Space
key={field.key}
style={{ display: "flex", marginBottom: 8 }}
align="start"
>
<Form.Item
{...field}
name={[field.name, "first"]}
fieldKey={[field.fieldKey, "first"]}
rules={[{ required: true, message: "Missing first name" }]}
>
<Input placeholder="First Name" />
</Form.Item>
<TimePicker
defaultValue={moment("12:08", "HH:mm")}
format={"HH:mm"}
// value={date}
onChange={(date, dateString) =>
changeDate1(date, dateString, field.key)
}
/>
<TimePicker
defaultValue={moment("12:10", "HH:mm")}
// value={fullDate2}
format={"HH:mm"}
onChange={(date, dateString) =>
changeDate2(date, dateString, field.key)
}
/>
<span>
difference -{" "}
{Object.keys(fullDate2).length
? myDiff(date, fullDate2, field.key)
: 0}
</span>
<MinusCircleOutlined
onClick={() => {
remove(field.name);
}}
/>
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
block
>
<PlusOutlined /> Add field
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};

问题:如何为每个生成的表单设置默认范围?
演示:https://codesandbox.io/s/runtime-bird-6mlfs?file=/index.js:313-3735

您应该为新密钥定义一个默认值:

const myDiff = (startSubEventTimes, endSubEventTimes, k) => {
// if (Object.keys(endSubEventTimes).length) {
const startTime = moment(startSubEventTimes[k] || "12:08", "HH:mm");
const endTime = moment(endSubEventTimes[k] || "12:10", "HH:mm");
const duration = moment.duration(endTime.diff(startTime));
const hours = parseInt(duration.asHours(), 0);
const minutes = parseInt(duration.asMinutes(), 0) - hours * 60;
if (!isNaN(hours) && !isNaN(minutes)) {
return `${hours}hours and  ${minutes}minutes`;
}
// }
};

如果您删除了一个字段,还应该从状态中删除[key]值,以防止下一个默认值被记忆。

但要正确更新,请查看@Rostyslav 的答案

但我仍然会将其发送给代码审查:https://codereview.stackexchange.com

将更改处理程序添加到添加字段按钮

<Button
type="dashed"
onClick={() => {
add();
changeDate1()
changeDate2()
}}
block
>

更新更改处理程序,以便如果没有传递值,则将默认日期字符串设置为";00:00";。若键也是未定义的(当您单击添加字段按钮时就是这种情况(,它将被计算为长度。

const changeDate1 = (momentDate, dateString="00:00", key) => {
console.log('changedate1', dateString, key);
key = key !== undefined ? key : Object.keys(date).length
setDate({ ...date, [key]: dateString });
};
const changeDate2 = (momentDate, dateString="01:00", key) => {
key = key !== undefined ? key : Object.keys(fullDate2).length
setFullDate2({ ...fullDate2, [key]: dateString });
};

最后一步是删除defaultValue属性并为TimePicker 添加值属性

<TimePicker
value={moment(date[field.key], format)}
format={format}
onChange={(date, dateString) =>
changeDate1(date, dateString, field.key)
}
/>
<TimePicker
value={moment(fullDate2[field.key],format)}
format={format}
onChange={(date, dateString) =>
changeDate2(date, dateString, field.key)
}
/>

删除一行可能会干扰我们在更改处理程序中设置默认键的方式。为了避免属性冲突,您可以找到最大道具而不是长度。maxKey表达式检查date是否有长度,因为当我们需要0时,对空对象调用max将导致infinity

const changeDate1 = (momentDate, dateString="00:00", key) => {
console.log('changedate1', dateString, key);
let maxKey = Object.keys(date).length ? Math.max(...Object.keys(date)) + 1 : 0
key = key !== undefined ? key : maxKey
setDate({ ...date, [key]: dateString });
};

最新更新