基本上,我们在类似下面的React类组件的componentDidMount()
生命周期方法中进行API调用
componentDidMount(){
//Here we do API call and do setState accordingly
}
但是在React v16.7.0中引入了钩子之后,不再有任何类组件。
我的查询是,我们到底需要在带有钩子的功能组件中进行API调用?
我们有没有类似componentDidMount()
的方法?
答案 0 :(得分:23)
是的,有类似(但不完全相同!)的带有钩子的componentDidMount
替代品,它是useEffect
钩子。
其他答案并不能真正回答您在哪里可以进行API调用的问题。您可以使用useEffect
进行API调用,并传入空数组或对象作为第二个参数来代替componentDidMount()
。这里的关键是第二个参数。如果您不提供空数组或对象作为第二个参数,则将在每个渲染器上调用API调用,并且该调用实际上将变为componentDidUpdate
。
如文档中所述:
传入空数组[]会告诉React您的效果不依赖于组件中的任何值,因此该效果仅在安装时运行,而在卸载时清除;它不会在更新上运行。
以下是一些需要进行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/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
例如,如果要显示某个用户的个人资料页面,其中每个页面都有一个userID状态/属性,则应将该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/react@16.8.1/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.8.1/umd/react-dom.development.js"></script>
<div id="app"></div>
您应该阅读useEffect
,以便了解您可以/不能使用它。
如丹·阿布拉莫夫(Dan Abramov)在this GitHub Issue上所说:
从长远来看,我们将不鼓励这种(useEffect)模式,因为它会鼓励比赛条件。例如-在通话开始和结束之间可能会发生任何事情,并且您可能会获得新的道具。相反,我们建议使用Suspense进行数据提取
所以请继续关注悬念!
答案 1 :(得分:2)
您可以使用像https://resthooks.io
这样的库来为您提供钩子然后获取数据变得非常简单:
const article = useResource(ArticleResource.singleRequest(), { id });
现在,您通过ID抓取了这篇文章。所有不满意的路径(加载,错误状态)分别由Suspense和Error boundaries处理。
要开始使用,请遵循以下简单指南:https://resthooks.io/docs/getting-started/installation
只需压缩7kb压缩包,这将为您节省很多痛苦,并且从长远来看,由于重复代码较少,因此可以减小捆绑包的大小。
答案 2 :(得分:2)
我只是将其发布为了解acc的一种简单方法。我的努力归功于Yangshun Tay的帖子,它涵盖了几乎所有内容。
代码:
useEffect(() => {
// here is where you make API call(s) or any side effects
fetchData('/data')
}, [] ) /** passing empty braces is necessary */
因此,在组件创建(装入)和销毁(卸下)时,useEffect(fn,[])
与空参数一起用作[]
会使fn()
触发一次值。
专业提示:
此外,如果您在此return()
中fn
进行某些操作,则它的生命周期与类组件的生命周期相同。
componentWillUnmount()
如果您希望在某些值更改时调用API,只需将该变量(存储值)传递到 useEffect(() => {
fetchData('/data')
return () => {
// this will be performed when component will unmount
resetData()
}
}, [] )
中的arguments数组中。
useEffect()
这将确保每当 useEffect(() => {
// perform your API call here
updateDetails();
},[prop.name]) /** --> will be triggered whenever value of prop.name changes */
的值更改时,挂钩中的函数都会被触发。
还要注意:该钩子在安装组件时也会首先被调用。因此,那时您的名称值可能处于初始状态,这在您看来是意外的。因此,您可以在函数中添加自定义条件,以避免不必要的API调用。
答案 3 :(得分:0)
将功能组件与hooks 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
组合。
答案 4 :(得分:0)
您也可以像这样使用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>
)
}