基本上我们在React类组件中的componentDidMount()
生命周期方法中进行API调用,如下所示
componentDidMount(){
//Here we do API call and do setState accordingly
}
但是在React v16.7.0中引入了钩子之后,就没有更多的类组件了。
我的查询是,我们究竟需要在带有钩子的功能组件中进行API调用?
我们有类似componentDidMount()
的方法吗?
是的,有一个类似的(但不是相同的!)替换componentDidMount
与钩子,它是useEffect
钩。
其他答案并没有真正回答您关于API调用位置的问题。您可以使用useEffect
进行API调用,并将空数组或对象作为第二个参数传入,以替换componentDidMount()
。这里的关键是第二个论点。如果不提供空数组或对象作为第二个参数,则将在每个渲染上调用API调用,它实际上变为componentDidUpdate
。
如文档中所述:
传入一个空数组[]输入告诉React你的效果不依赖于组件中的任何值,因此该效果只能在mount上运行并在unmount上清理;它不会在更新时运行。
以下是您需要进行API调用的场景的一些示例:
尝试运行下面的代码并查看结果。
function User() {
const [firstName, setFirstName] = React.useState(null);
const [lastName, setLastName] = React.useState(null);
React.useEffect(() => {
fetch('https://randomuser.me/api/')
.then(results => results.json())
.then(data => {
const {name} = data.results[0];
setFirstName(name.first);
setLastName(name.last);
});
}, []); // <-- Have to pass in [] here!
return (
<div>
Name: {!firstName || !lastName ? 'Loading...' : `${firstName} ${lastName}`}
</div>
);
}
ReactDOM.render(<User />, document.querySelector('#app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>
如果您要显示用户的配置文件页面,其中每个页面都具有userID状态/ prop,则应将该ID作为值传递到useEffect
的第二个参数中,以便为新用户ID重新获取数据。 componentDidMount
在这里是不够的,因为如果你直接从用户A转到用户B的个人资料,该组件可能不需要重新安装。
在传统的课程方式中,你会这样做:
componentDidMount() {
this.fetchData();
}
componentDidUpdate(prevProps, prevState) {
if (prevState.id !== this.state.id) {
this.fetchData();
}
}
使用钩子,那将是:
useEffect(() => {
this.fetchData();
}, [id]);
尝试运行下面的代码并查看结果。例如,将id更改为2,以查看useEffect
是否再次运行。
function Todo() {
const [todo, setTodo] = React.useState(null);
const [id, setId] = React.useState(1);
React.useEffect(() => {
if (id == null || id === '') {
return;
}
fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
.then(results => results.json())
.then(data => {
setTodo(data);
});
}, [id]); // useEffect will trigger whenever id is different.
return (
<div>
<input value={id} onChange={e => setId(e.target.value)}/>
<br/>
<pre>{JSON.stringify(todo, null, 2)}</pre>
</div>
);
}
ReactDOM.render(<Todo />, document.querySelector('#app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>
你应该阅读useEffect
,以便你知道你能做什么/不能做什么。
正如Dan Abramov在this GitHub Issue上所说:
从长远来看,我们会阻止这种(useEffect)模式,因为它会鼓励竞争条件。比如 - 你的通话开始和结束之间可能发生任何事情,你可能会得到新的道具。相反,我们会建议使用Suspense进行数据提取
所以请继续关注悬疑!
您可以使用为https://resthooks.io提供钩子的库
然后获取您的数据变得如此简单:
const article = useResource(ArticleResource.singleRequest(), { id });
现在你抓住了id的文章。所有非幸福路径(加载,错误状态)分别由Suspense和Error boundaries处理。
要开始使用这个简单的指南:https://resthooks.io/docs/getting-started/installation
只需7kb gzip,这将为您节省很多痛苦,并且从长远来看,由于重复代码较少,您的捆绑大小会降低。
当您使用带有钩子API的功能组件时,您可以使用useEffect()
方法来产生副作用。每当由于这些副作用而更新状态时,组件将重新渲染。
import { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
例如,您可以在异步请求的回调函数中调用setCount
。执行回调时,状态将更新,React将重新呈现组件。同样来自文档:
小费
如果您熟悉React类生命周期方法,则可以将useEffect Hook视为
componentDidMount
,componentDidUpdate
和componentWillUnmount
的组合。
您也可以使用use-http
:
import useFetch from 'use-http'
function App() {
// add whatever other options you would add to `fetch` such as headers
const options = {
method: 'POST',
body: {}, // whatever data you want to send
}
var [data, loading, error] = useFetch('https://example.com', options)
// want to use object destructuring? You can do that too
var { data, loading, error } = useFetch('https://example.com', options)
if (error) {
return 'Error!'
}
if (loading) {
return 'Loading!'
}
return (
<code>
<pre>{data}</pre>
</code>
)
}