首页 > 解决方案 > 如何在类组件中使用带有 useState 的回调,如 setState?

问题描述

我有一个用户可以编辑的文本字段行表,还可以添加新行。当用户单击“添加”按钮添加新行时,我想将焦点设置在最后一行的第一个文本字段上,即刚刚创建的行。这是一些示例代码:

interface Row {
    id: string;
    desc: string;
    firstTextFieldRef: React.MutableRefObject<undefined>;
};

const defaultRow: Row = {
    id: '',
    desc: '',
    firstTextFieldRef: useRef(),
};

const [rows, setRows] = useState<Row[]>([Object.assign(defaultRow, {})]);

当用户单击 addRow 按钮时,我调用此函数:

const addHandler = () => {
    setRows([...rows, Object.assign(defaultRow, {})]);

    // use setTimeout because setRows^^ is async and rows aren't updated immediately
    // other solutions exist, but this works ok for now
    setTimeout(() => {
        const ref = rows[rows.length - 1].firstTextFieldRef;
        if (ref.current) ref.current.focus();
    }, 100);
};

我想避免在这里使用 setTimeout。我知道我可以像这样使用 useEffect :

useEffect(() => {
    const ref = rows[rows.length - 1].firstTextFieldRef;
    if (ref.current) ref.current.focus();
}, [rows]);

但是,添加新行并不是行数组更改的唯一时间。每当用户连续输入输入时,行数组都会更新。

有什么想法吗?

标签: javascriptreactjsreact-hooks

解决方案


但是,添加新行并不是行数组更改的唯一时间。

如果您不关心行更改,而只更改数组长度(即新行),请使用它来触发效果:

useEffect(() => {
    const ref = rows[rows.length - 1].firstTextFieldRef;
    if (ref.current) ref.current.focus();
}, [rows.length]);

推荐阅读