我在哪里可以使用挂钩进行 API 调用?
Where can I make API call with hooks in react?
基本上我们在 React class 组件中 API 调用 componentDidMount()
生命周期方法
componentDidMount(){
//Here we do API call and do setState accordingly
}
但是React v16.7.0引入hooks后,大部分都是函数式组件
我的问题是,我们到底需要在哪里 API 调用带钩子的功能组件?
我们有类似componentDidMount()
的方法吗?
当您使用带钩子的功能组件时 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 将重新渲染组件。同样来自文档:
Tip
If you’re familiar with React class lifecycle methods, you can think
of useEffect Hook as componentDidMount
, componentDidUpdate
, and
componentWillUnmount
combined.
是的,componentDidMount
有一个类似的(但不一样!)替代品,它是 useEffect
钩子。
其他答案并没有真正回答您关于在哪里可以拨打 API 电话的问题。您可以通过使用 useEffect
和 传入一个空数组或对象作为第二个参数来进行 API 调用 作为 componentDidMount()
的替代。这里的关键是第二个参数。如果您不提供空数组或对象作为第二个参数,则 API 调用将在每次渲染时调用,它实际上变成了 componentDidUpdate
.
如文档中所述:
Passing in an empty array [] of inputs tells React that your effect doesn’t depend on any values from the component, so that effect would run only on mount and clean up on unmount; it won’t run on updates.
以下是您需要进行 API 调用的一些场景示例:
API 在 Mount 上严格调用
尝试运行使用下面的代码并查看结果。
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>
API 每当 Prop/State 发生变化时调用
例如,如果您要显示用户的个人资料页面,其中每个页面都有一个用户 ID state/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/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
以便了解您 can/cannot 用它做什么。
悬疑
正如 Dan Abramov 在 this GitHub Issue 上所说:
Longer term we'll discourage this (useEffect) pattern because it encourages race conditions. Such as — anything could happen between your call starts and ends, and you could have gotten new props. Instead, we'll recommend Suspense for data fetching
敬请期待 Suspense!
您可以使用为您提供钩子的库 https://resthooks.io
然后获取数据变得非常简单:
const article = useResource(ArticleResource.detail(), { id });
现在你通过id抓到了文章。所有不愉快的路径(加载、错误状态)分别由 Suspense 和 Error boundaries 处理。
要开始,请遵循这个简单的指南:https://resthooks.io/docs/getting-started/installation
gzip 压缩后只有 7kb,这将为您省去很多麻烦,并且从长远来看 运行 由于重复代码较少,因此可以降低包的大小。
您也可以使用 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>
)
}
我只是 post 将此作为理解 acc 的更简单方法。我的努力。感谢 Yangshun Tay post,它涵盖了几乎所有内容。
API 调用组件挂载
代码:
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()
生命周期与 class 组件的生命周期相同。
useEffect(() => {
fetchData('/data')
return () => {
// this will be performed when component will unmount
resetData()
}
}, [] )
API 当某些值改变时调用
如果您想在某些值更改时调用 API,只需将该变量(存储值)传递到 useEffect()
中的参数数组即可。
useEffect(() => {
// perform your API call here
updateDetails();
},[prop.name]) /** --> will be triggered whenever value of prop.name changes */
这将确保每当 prop.name
的值发生变化时,您的钩子函数就会被触发。
还要注意:这个钩子在组件挂载的时候也会被初始调用。所以那时你的名字值可能处于初始状态,这在你看来是意想不到的。因此,您可以在函数中添加自定义条件以避免不必要的 API 调用。
基本上我们在 React class 组件中 API 调用 componentDidMount()
生命周期方法
componentDidMount(){
//Here we do API call and do setState accordingly
}
但是React v16.7.0引入hooks后,大部分都是函数式组件
我的问题是,我们到底需要在哪里 API 调用带钩子的功能组件?
我们有类似componentDidMount()
的方法吗?
当您使用带钩子的功能组件时 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 将重新渲染组件。同样来自文档:
Tip
If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as
componentDidMount
,componentDidUpdate
, andcomponentWillUnmount
combined.
是的,componentDidMount
有一个类似的(但不一样!)替代品,它是 useEffect
钩子。
其他答案并没有真正回答您关于在哪里可以拨打 API 电话的问题。您可以通过使用 useEffect
和 传入一个空数组或对象作为第二个参数来进行 API 调用 作为 componentDidMount()
的替代。这里的关键是第二个参数。如果您不提供空数组或对象作为第二个参数,则 API 调用将在每次渲染时调用,它实际上变成了 componentDidUpdate
.
如文档中所述:
Passing in an empty array [] of inputs tells React that your effect doesn’t depend on any values from the component, so that effect would run only on mount and clean up on unmount; it won’t run on updates.
以下是您需要进行 API 调用的一些场景示例:
API 在 Mount 上严格调用
尝试运行使用下面的代码并查看结果。
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>
API 每当 Prop/State 发生变化时调用
例如,如果您要显示用户的个人资料页面,其中每个页面都有一个用户 ID state/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/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
以便了解您 can/cannot 用它做什么。
悬疑
正如 Dan Abramov 在 this GitHub Issue 上所说:
Longer term we'll discourage this (useEffect) pattern because it encourages race conditions. Such as — anything could happen between your call starts and ends, and you could have gotten new props. Instead, we'll recommend Suspense for data fetching
敬请期待 Suspense!
您可以使用为您提供钩子的库 https://resthooks.io
然后获取数据变得非常简单:
const article = useResource(ArticleResource.detail(), { id });
现在你通过id抓到了文章。所有不愉快的路径(加载、错误状态)分别由 Suspense 和 Error boundaries 处理。
要开始,请遵循这个简单的指南:https://resthooks.io/docs/getting-started/installation
gzip 压缩后只有 7kb,这将为您省去很多麻烦,并且从长远来看 运行 由于重复代码较少,因此可以降低包的大小。
您也可以使用 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>
)
}
我只是 post 将此作为理解 acc 的更简单方法。我的努力。感谢 Yangshun Tay post,它涵盖了几乎所有内容。
API 调用组件挂载
代码:
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()
生命周期与 class 组件的生命周期相同。
useEffect(() => {
fetchData('/data')
return () => {
// this will be performed when component will unmount
resetData()
}
}, [] )
API 当某些值改变时调用
如果您想在某些值更改时调用 API,只需将该变量(存储值)传递到 useEffect()
中的参数数组即可。
useEffect(() => {
// perform your API call here
updateDetails();
},[prop.name]) /** --> will be triggered whenever value of prop.name changes */
这将确保每当 prop.name
的值发生变化时,您的钩子函数就会被触发。
还要注意:这个钩子在组件挂载的时候也会被初始调用。所以那时你的名字值可能处于初始状态,这在你看来是意想不到的。因此,您可以在函数中添加自定义条件以避免不必要的 API 调用。