我正在处理一个表单,其中包含日历条目 - 日期和时间。代码如下:
{dates.map((d, i) => (
<div className="date-time-entry" key={i}>
<div className="date-picker">
<DatePicker
selected={new Date(d.startDate)}
dateFormat="dd MMM yyyy"
onChange={date => {
const newDates = [...dates]
newDates[i].startDate = date
setDates(newDates)
}}
/>
to
<DatePicker
selected={new Date(d.endDate)}
dateFormat="dd MMM yyyy"
onChange={date => {
const newDates = [...dates]
newDates[i].endDate = date
setDates(newDates)
}}
/>
{i ? (
<span
onClick={() => {
const newDates = dates.filter((d, k) => k !== i)
setDates(newDates)
}}
>
<FontAwesomeIcon icon={faTimes} />
</span>
) : null}
</div>
{dates[i].times.map((t, j) => {
return (
<div className="time-picker" key={j}>
at
<input
ref={(input) => { nameInput = input }}
value={t.start}
onChange={e => {
const newDates = [...dates]
newDates[i].times[j].start = e.target.value
setDates(newDates)
}}
/>{' '}
to{' '}
<input
ref={(input) => { nameInput = input }}
value={t.end}
onChange={e => {
const newDates = [...dates]
newDates[i].times[j].end = e.target.value
setDates(newDates)
}}
/>
<span
onClick={() => {
const newTimes = dates[i].times.filter((t, k) => k !== j)
const newDates = [...dates]
newDates[i].times = newTimes
setDates(newDates)
}}
>
<FontAwesomeIcon icon={faTimes} />
</span>
</div>
)
})}
<div
className="add-time"
onClick={() => {
const newDates = [...dates]
newDates[i].times = [
...newDates[i].times,
{ start: '12:00', end: '13:00' }
]
setDates(newDates)
}}
>
Add Time
</div>
</div>
)
)}
然后是
useState()
钩子(Hook)定义为:const [dates, setDates] = useState([
{
startDate: new Date(),
endDate: new Date(),
times: [{ start: '12:00', end: '13:00' }]
}
])
我遇到的问题是,无论何时调用 onChange - 每次击键都会发生重新渲染并且我的组件失去焦点。
我尝试使用
onBlur
和 defaultValue
代替 onChange
,但还有一个焦点问题 - 焦点切换需要两次点击,因为第一次被重新渲染消耗。我还尝试添加超时来处理
onBlur
“丢失”一键,如下所示:<input
defaultValue={t.start}
onBlur={e => {
const value = e.target.value
timeout = setTimeout(() => {
const newDates = [...dates]
newDates[i].times[j].start = value
setDates(newDates)
}, 0)
}}
onFocus={() => {
clearTimeout(timeout)
}}
/>
最后一个版本不再失去焦点,而是失去状态更新。关于如何更好地处理这个问题,或者甚至修复我现有的代码的任何建议?
最佳答案
我认为拥有以下代码不是一个好主意:
{dates[i].times.map((t, j) => {
return (
<div className="time-picker" key{j}>
at
<input
ref={(input) => { nameInput = input }}
value={t.start}
onChange={e => {
const newDates = [...dates]
newDates[i].times[j].start = e.target.value
setDates(newDates)
}}
/>{' '}
to{' '}
<input
ref={(input) => { nameInput = input }}
value={t.end}
onChange={e => {
const newDates = [...dates]
newDates[i].times[j].end = e.target.value
setDates(newDates)
}}
/>
<span
onClick={() => {
const newTimes = dates[i].times.filter((t, k) => k !== j)
const newDates = [...dates]
newDates[i].times = newTimes
setDates(newDates)
}}
>
<FontAwesomeIcon icon={faTimes} />
</span>
</div>
)
})}
每次,日期发生任何变化,它都会再次重新渲染所有组件。
您应该将每次选择器作为一个单独的组件,如下所示:
const changeHandler = (i, j, x, val) => {
const newDates = [...dates]
newDates[i].times[j][x] = val
setDates(newDates)
}
const clickHandler = (i, j) => {
const newTimes = dates[i].times.filter((t, k) => k !== j)
const newDates = [...dates]
newDates[i].times = newTimes
setDates(newDates)
}
{dates[i].times.map((t, j) => {
return (
<MyTimePicker time={t} k={"time_" + j} changeHandler={( val, x="start" ) => changeHandler(i, j, x, val)} clickHandler={() => clickHandler(i, j)}>
)
})}
在另一个文件“my-timepicker.js”中,你应该定义你的组件:
import React, { useRef } from "react";
const areEqual = (prevProps, nextProps) => {
if(JSON.stringify(prevProps.time) == JSON.stringify(nextProps.time)) return true;
return false;
}
const MyTimePicker = React.memo(({changeHandler, clickHandler, time }) => {
const atInputRef = useRef();
const toInputRef = useRef();
return (
<div className="time-picker">
at
<input
ref={atRef}
value={time.start}
onChange={e => {
changeHandler(e.target.value)
}}
/>{' '}
to{' '}
<input
ref={toRef}
value={time.end}
onChange={e => {
changeHandler(e.target.value, "end")
}}
/>
<span
onClick={clickHandler}
>
<FontAwesomeIcon icon={faTimes} />
</span>
</div>
)
}, areEqual);
关于reactjs - React 表单失去了对更新的关注,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/60588024/