javascript - 对 useEffect 感到困惑
问题描述
我正在构建我的第一个 Custom React Hook,并且对我认为代码的一个简单方面感到困惑:
export const useFetch = (url, options) => {
const [data, setData] = useState();
const [loading, setLoading] = useState(true);
const { app } = useContext(AppContext);
console.log('** Inside useFetch: options = ', options);
useEffect(() => {
console.log('**** Inside useEffect: options = ', options);
const fetchData = async function() {
try {
setLoading(true);
const response = await axios.get(url, options);
if (response.status === 200) {
setData(response.data);
}
} catch (error) {
throw error;
} finally {
setLoading(false);
}
};
fetchData();
}, []);
return { loading, data };
};
我传递给useFetch
两个参数:一个 url 和一个headers
包含 AWS Cognito 授权密钥的对象,如下所示:(Authorization: eyJraWQiOiJVNW...
为简洁起见)
当我这样做时,options
对象确实存在于内部附近useFetch
但在useEffect
构造内部它是空的。然而,url
字符串在两种情况下都正确填充。
这对我来说毫无意义。可能有人知道为什么会这样吗?
解决方案
下面的代码实现显示它按预期工作。
async/await 已转换为 Promise,但应该具有相同的行为。
“Inside use fetch”输出3次:
- 在安装 (
useEffect(()=>..., []
) - 第一次状态改变后 (
setLoading(true)
) - 第二次状态变化后 (
setLoading(false)
)
并且“内部使用效果”在 mount ( useEffect(()=>..., []
)时输出 1 次
由于这种方式对您不起作用,这可能意味着当组件安装时,选项尚不可用。
当您说当您将选项作为依赖项时,您确认了这一点,useEffect 被调用两次,第一次获取失败(很可能是因为缺少选项)。
我很确定您会发现使用自定义挂钩的组件父项中的选项存在问题。
const axios = {
get: (url, options) => {
return new Promise(resolve => setTimeout(() => resolve({ status: 200, data: 'Hello World' }), 2000));
}
};
const AppContext = React.createContext({ app: null });
const useFetch = (url, options) => {
const [data, setData] = React.useState();
const [loading, setLoading] = React.useState(true);
const { app } = React.useContext(AppContext);
console.log('** Inside useFetch: options = ', JSON.stringify(options));
React.useEffect(() => {
console.log('**** Inside useEffect: options = ', JSON.stringify(options));
const fetchData = function () {
setLoading(true);
const response = axios.get(url, options)
.then(response => {
if (response.status === 200) {
setData(response.data);
}
setLoading(false);
})
.catch(error => {
setLoading(false);
throw error;
});
};
fetchData();
}, []);
return { loading, data };
};
const App = ({url, options}) => {
const { loading, data } = useFetch(url, options);
return (
<div
style={{
display: 'flex', background: 'red',
fontSize: '20px', fontWeight: 'bold',
justifyContent: 'center', alignItems: 'center',
width: 300, height: 60, margin: 5
}}
>
{loading ? 'Loading...' : data}
</div>
);
};
ReactDOM.render(
<App
url="https://www.dummy-url.com"
options={{ headers: { Authorization: 'eyJraWQiOiJVNW...' } }}
/>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root" />
推荐阅读
- mysql - 为什么mysql workbench 8.0会因为不关闭if而抛出错误,尽管所有“if”都已正确关闭?
- javascript - 是否可以在 html 文件中动态加载来自 js 文件的图像?
- prolog - labeling/2 如何从域的中点生成解决方案?
- c# - ASP.NET Web api 上的文件上传端点损坏文件
- php - 发布方法在不同的服务器中无法正常工作
- javascript - 为什么我无法访问使用 Node.js/Express-TypeScript 的 SSL 证书?
- php - laravel 5.2 图像无法加载
- aws-lambda - 如何存储来自 Amazon Lex 的用户输入(话语)?
- html - 由于图像,Chrome中的Angular Firebase滚动问题
- python - 音频识别:将音频示例的大小调整为相同的长度