如何使用React功能组件,防止列表中的输入重新呈现(并放松对输入的关注)



我有一个要在列表中呈现的项目列表(openItems(。对于列表中的每个项目,我都需要一个输入来更改打开项目的一个属性(持续时间(。问题是,每次更改属性时,父项(openItems(及其所有子项(包括输入(都会重新调用。这会使输入失去焦点。

我正试着思考这个模式应该如何实现(使用功能组件(,以避免崩溃。我尝试使用React.memo,但随着数据的变化,这没有什么区别。

下面是它当前实现方式的精简代码片段。(我使用的是Antd组件(

const Page = () => {
const dispatch = useDispatch();
const openItems = ...get items from state
const setMs = (id: string, ms: number) => {
dispatch(changeDuration({ id, duration: ms }));
}
const InputMs: React.FC<{ row: RowInterface }> = (props) => (
<InputNumber
defaultValue={props.row.durationMs}
onChange={(v) => setMs(props.row.id, v)}
/>
)
const RowContent: React.FC<{ row: RowInterface }> = (props) => (
<>
<SmallText>Duration in ms:</SmallText>
<InputMs row={props.row} />
</>
);
const Rows: React.FC<RowProps> = (props) => {
return (
<>
{props.data.map((row) =>
<RowContent row={row} />
)}
</>
)
};
return( <Rows data={openItems} /> )
};
export default Page;

基于这个答案,我还尝试将输入作为一个单独的组件,但结果相同:

const InputMs: React.FC<{ row: RowInterface  }> = (props) => {
const dispatch = useDispatch();
const setMs = (id: string, ms: number) => {
dispatch(changeDuration({ id, duration: ms }));
}
return (
<InputNumber
defaultValue={props.row.durationMs}
onChange={(v) => setMs(props.row.id, v)}
/>
)
}
const Page = () => {
const openItems = ...get items from state;
const RowContent: React.FC<{ row: RowInterface  }> = (props) => (
<>
<SmallText>Duration in ms:</SmallText>
<InputMs row={props.row} />
</>
);
const Rows: React.FC<RowProps> = (props) => {
return (
<>
{props.data.map((row) =>
<RowContent row={row} />
)}
</>
)
};
return (<Rows data={openItems} />)
};
export default Page;

现在我已经决定对输入进行临时更新。(在这里找到解决方案(

CCD_ 2现在改变本地状态,并且CCD_。通过这种方式,用户可以按预期使用输入。

const InputMs: React.FC<{ row: RowProps}> = (props) => {
const [value, setValue] = useState<number>();
const dispatch = useDispatch();
const setState = (id: string) => {
if(value){
dispatch(changeDuration({ id, duration: value }));
setValue(undefined);
}
}
return (
<InputNumber
defaultValue={props.row.durationMs}
onChange={(v) => setValue(v)}
onBlur={(v) => setState(props.row.id)}
/>
)
}

这里发生的事情是,您正在另一个组件内部定义子组件。这意味着,当Page由于redux状态的更改而重新渲染时,您的InputMsRowContentRows组件都会重新创建。它们将卸载和重新装载,并失去集中状态,因为它现在是一个全新的组件实例。

你已经走到了一半,因为你已经找到了告诉你这一点的链接答案。但是必须移动所有内部组件。您只移动了InputMs,但仍在重新创建的RowsRowContent内部调用它。

您希望在文件的顶层定义所有组件。

也可以将这些代码段编写为作为函数调用的普通函数,而不是作为JSX元素调用它们。例如:

const Page = () => {
const openItems = ...get items from state;
const renderRow = (row: RowInterface) => (
<>
<SmallText>Duration in ms:</SmallText>
<InputMs row={row} />
</>
);
return (
<>
{openItems.map(renderRow)}
</>
);
}

相关内容

最新更新