如何处理返回陈旧事件处理程序的 React 挂钩
How do deal with React hooks returning stale event handlers
我正在尝试弄清楚如何处理挂钩返回的陈旧事件处理程序。首先,当组件首次呈现时,它会向 api 发出异步请求以获取凭据。然后在对话框中按下提交按钮以创建资源时使用这些凭据。问题是对话框提交按钮单击事件处理程序的凭据未定义,即使在获取凭据后也是如此。
credentials.js
import { useEffect } from 'react';
import { api } from './api';
export const useCredentials = (setCredentials) => {
useEffect(() => {
const asyncGetCredentials = async () => {
const result = await api.getCredentials();
if (result) {
setCredentials(result);
}
};
asyncGetCredentials().then();
}, []);
return credentials;
}
useComponent.js
import { useEffect, useRef, useCallback, useState } from 'react';
import { useCredentials } from './credentials';
import { createResource } from './resources';
import { useDialog } from './useDialog';
export const useComponent = () => {
const { closeDialog } = useDialog();
const [credentials, setCredentials] = useState();
useCredentials(setCredentials);
const credentialsRef = useRef(credentials);
useEffect(() => {
// logs credentials properly after they have been fetched
console.log(credentials)
credentialsRef.current = credentials;
}, [credentials]);
const createResourceUsingCredentials = useCallback(
async function () {
// credentials and credentialsRef.current are both undefined
// even when the function is called after the credentials
// have already been fetched.
console.log(credentials);
console.log(credentialsRef.current);
createResource(credentialsRef.current);
}, [credentials, credentialsRef, credentialsRef.current]
);
const onDialogSubmit = useCallback(
async function () {
await createResourceUsingCredentials();
closeDialog();
}, [
credentials,
credentialsRef,
credentialsRef.current,
createResourceUsingCredentials,
],
);
return {
onDialogSubmit,
}
}
试试这个方法
export const useCredentials = (setCredentials) => {
useEffect(() => {
const asyncGetCredentials = async () => {
const result = await api.getCredentials();
if (result) {
setCredentials(result);
}
};
asyncGetCredentials().then();
}, []);
}
export const useComponent = () => {
const { closeDialog } = useDialog();
const [credentials, setCredentials] = useState(); // new add
useCredentials(setCredentials);
....
}
为什么要增加复杂性,总是 return 函数并在函数内部检查 credentials
export const useComponent = () => {
const { closeDialog } = useDialog();
const credentials = useCredentials();
// correctly logs undefined at first and updated credentials
// when they are asynchronously received from the api.
console.log(credentials);
async function createResourceUsingCredentials() {
createResource(credentials);
}
let onClickDialogSubmit = async () => {
if (credentials) {
await createResourceUsingCredentials();
closeDialog();
}
};
return {
onClickDialogSubmit,
}
}
我发现问题出在 useCredentials 挂钩实现中。如果请求已经在进行中,它会阻止对 api 的任何进一步请求。由于此功能的实施不佳,如果呈现了使用该挂钩的 1 个以上组件,则只有首先呈现的组件才会更新凭据。我更改了 useCredentials 挂钩,以便它订阅全局状态(具有凭据),这样无论哪个组件启动请求,所有组件都将在请求完成时获得凭据。 https://simbathesailor007.medium.com/debug-your-reactjs-hooks-with-ease-159691843c3a 对调试这个问题帮助很大。
我正在尝试弄清楚如何处理挂钩返回的陈旧事件处理程序。首先,当组件首次呈现时,它会向 api 发出异步请求以获取凭据。然后在对话框中按下提交按钮以创建资源时使用这些凭据。问题是对话框提交按钮单击事件处理程序的凭据未定义,即使在获取凭据后也是如此。
credentials.js
import { useEffect } from 'react';
import { api } from './api';
export const useCredentials = (setCredentials) => {
useEffect(() => {
const asyncGetCredentials = async () => {
const result = await api.getCredentials();
if (result) {
setCredentials(result);
}
};
asyncGetCredentials().then();
}, []);
return credentials;
}
useComponent.js
import { useEffect, useRef, useCallback, useState } from 'react';
import { useCredentials } from './credentials';
import { createResource } from './resources';
import { useDialog } from './useDialog';
export const useComponent = () => {
const { closeDialog } = useDialog();
const [credentials, setCredentials] = useState();
useCredentials(setCredentials);
const credentialsRef = useRef(credentials);
useEffect(() => {
// logs credentials properly after they have been fetched
console.log(credentials)
credentialsRef.current = credentials;
}, [credentials]);
const createResourceUsingCredentials = useCallback(
async function () {
// credentials and credentialsRef.current are both undefined
// even when the function is called after the credentials
// have already been fetched.
console.log(credentials);
console.log(credentialsRef.current);
createResource(credentialsRef.current);
}, [credentials, credentialsRef, credentialsRef.current]
);
const onDialogSubmit = useCallback(
async function () {
await createResourceUsingCredentials();
closeDialog();
}, [
credentials,
credentialsRef,
credentialsRef.current,
createResourceUsingCredentials,
],
);
return {
onDialogSubmit,
}
}
试试这个方法
export const useCredentials = (setCredentials) => {
useEffect(() => {
const asyncGetCredentials = async () => {
const result = await api.getCredentials();
if (result) {
setCredentials(result);
}
};
asyncGetCredentials().then();
}, []);
}
export const useComponent = () => {
const { closeDialog } = useDialog();
const [credentials, setCredentials] = useState(); // new add
useCredentials(setCredentials);
....
}
为什么要增加复杂性,总是 return 函数并在函数内部检查 credentials
export const useComponent = () => {
const { closeDialog } = useDialog();
const credentials = useCredentials();
// correctly logs undefined at first and updated credentials
// when they are asynchronously received from the api.
console.log(credentials);
async function createResourceUsingCredentials() {
createResource(credentials);
}
let onClickDialogSubmit = async () => {
if (credentials) {
await createResourceUsingCredentials();
closeDialog();
}
};
return {
onClickDialogSubmit,
}
}
我发现问题出在 useCredentials 挂钩实现中。如果请求已经在进行中,它会阻止对 api 的任何进一步请求。由于此功能的实施不佳,如果呈现了使用该挂钩的 1 个以上组件,则只有首先呈现的组件才会更新凭据。我更改了 useCredentials 挂钩,以便它订阅全局状态(具有凭据),这样无论哪个组件启动请求,所有组件都将在请求完成时获得凭据。 https://simbathesailor007.medium.com/debug-your-reactjs-hooks-with-ease-159691843c3a 对调试这个问题帮助很大。