我正在尝试创建一个 promisify 风格的钩子,其想法是最终将其与 Redux Toolkit 一起使用,以允许使用新的 React 19
use
钩子。
这是这个东西如何工作的原理:
function usePromise(input: {
isLoading: true,
data: null
} | {
isLoading: false,
data: string;
}) {
// Store the resolve function in a ref
const resRef = useRef<(data: string) => void>(null);
// Create a new promise
// Store the resolve function in the ref
const promiseRef = useRef(
new Promise((res) => {
resRef.current = res;
//res("xxx") // 👈 this will resolve though
})
);
// When input changes, if there is data, resolve the promise
useEffect(() => {
if (!input.isLoading) {
resRef.current?.(input.data);
}
}, [input]);
// Return the promise
return promiseRef.current;
}
用法如下:
export function MyComponent() {
const [value, setValue] = useState<null | string>(null);
const prom = usePromise(value ? {
isLoading: false,
data: value
} : {
isLoading: true,
data: null
});
prom.then((v) => alert(v))
return <div >
<button onClick={() => setValue("123")}>Click me</button>
</div>
}
在这里,我希望当我们单击按钮时,承诺将得到解决,并且我们会看到警报。然而,事实并非如此。
这是怎么回事?
我在这里复制了这个问题:https://github.com/dwjohnston/react-promise-issue
您的问题是,每次钩子运行时您都会创建一个新的 Promise,并将
resRef.current
设置为最后一个 Promise 的解析器函数。然而,只有传递到 useRef
钩子的第一个承诺才会存储在 promiseRef.current
中。
要解决此问题,避免重新创建承诺:
function usePromise(input) {
const resRef = useRef();
const promiseRef = useRef();
if (!promiseRef.current) {
promiseRef.current = new Promise(resolve => {
resRef.current = resolve;
});
}
useEffect(() => {
if (!input.isLoading) {
resRef.current(input.data);
}
}, [input]);
return promiseRef.current;
}