【发布时间】:2021-07-27 12:39:06
【问题描述】:
所以基本上我有一个去抖输入组件,它公开了 2 个 ref 方法,一个用于清除输入的值,一个用于将其设置为字符串。
问题是,使用父组件的 ref 方法不起作用。
代码:
import React, { ChangeEvent, forwardRef, useImperativeHandle, useState } from 'react';
import { TextInput } from 'components/common';
import { useDebounce } from 'utilities/CustomHooks';
import Logger from 'utilities/Logger';
export type DebouncedInputRef = {
clearValue: () => void;
setValue: (value: string) => void;
};
export const DebouncedInput = forwardRef(
(
{ onChange, ...textInputProps }: ComponentProps.DebouncedInputProps,
ref,
) => {
const [textInputValue, setTextInputValue] = useState('');
const debouncedOnChange = useDebounce((newValue: string) => {
onChange && onChange(newValue);
}, 1000);
useImperativeHandle(
ref,
(): DebouncedInputRef => {
return {
clearValue: () => {
setTextInputValue('');
},
setValue: (newValue: string) => {
Logger.debug('DebouncedInput', 'setValue fired with', newValue);
setTextInputValue(newValue);
},
};
},
);
return (
<div>
{Logger.debug('DebouncedInput', 'in render value', textInputValue)}
<TextInput
{...textInputProps}
value={textInputValue}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
setTextInputValue(e.target.value);
debouncedOnChange(e.target.value);
}}
/>
</div>
);
},
);
调用ref方法的代码如下:
const ListProducts = () => {
const debouncedInputRef = useRef<DebouncedInputRef>();
useEffect(() => {
debouncedInputRef?.current && debouncedInputRef.current.setValue('Test');
}, []);
return (
<DebouncedInput
ref={debouncedInputRef}
/>
);
};
setValue 中的 Logger.debug 打印来自父组件的传入值。
render 中的 Logger.debug 也运行了两次,表示在调用 setTextInputValue 后立即重新渲染。
但是,渲染过程中状态变量的值和之前一样。
基本上,setValue 运行,但是状态变量没有更新,我也不知道为什么。
非常欢迎任何指点。
更新:
好的,所以我开始工作了。 基本上,我的 ListProducts 组件有一些额外的细节:
const ListProducts = () => {
const [loading, setLoading] = useState(false);
const debouncedInputRef = useRef<DebouncedInputRef>();
const mockApiCall = () => {
setLoading(true);
// call API and then
setLoading(false);
};
useEffect(() => {
debouncedInputRef?.current && debouncedInputRef.current.setValue('Test');
mockApiCall();
}, []);
if (loading) {
return <div>Spinner here</div>;
}
return (
<DebouncedInput
ref={debouncedInputRef}
/>
);
};
我认为问题在于,ref 捕获了初始 DebouncedInput,然后调用了 API,该 API 返回了微调器并从 DOM 中删除了 Debounced Input。
后来API做完,又渲染了一遍,但我猜是不同的DOM元素?
我不知道为什么会这样,但确实如此。我很高兴知道究竟是什么导致了这个问题。
这是一个code sandbox example,其中包含有效和无效的示例。
如果有人能详细说明无效示例中的问题究竟是什么,我将不胜感激:)
【问题讨论】:
-
请添加一个codesandbox可重现的例子
-
我搞定了。我会将问题作为答案发布,但这里是代码框,适用于工作和不工作的示例:link
-
虽然,我仍然不确定“不工作示例”中的问题是什么。任何解释都会非常有帮助:)
-
你应该只更新你的帖子,而不是在自我发布的答案中提问
-
它不工作的原因是由于渲染时间,在您的“工作示例”中,您实际上在每个渲染器上重新安装了组件,您错过了一个渲染器来更新您的参考。它与这个问题有关:stackoverflow.com/questions/60476155/…
标签: javascript reactjs typescript react-hooks