javascript React Hooks - 发出 Ajax 请求
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/53059059/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
React Hooks - Making an Ajax request
提问by peter flanagan
I have just began playing around with React hooks and am wondering how an AJAX request should look?
我刚刚开始玩 React 钩子,想知道 AJAX 请求应该是什么样子?
I have tried many attempts, but am unable to get it to work, and also don't really know the best way to implement it. Below is my latest attempt:
我尝试了很多尝试,但无法让它工作,也不知道实现它的最佳方法。以下是我最近的尝试:
import React, { useState, useEffect } from 'react';
const App = () => {
const URL = 'http://api.com';
const [data, setData] = useState({});
useEffect(() => {
const resp = fetch(URL).then(res => {
console.log(res)
});
});
return (
<div>
// display content here
</div>
)
}
回答by Paul Fitzgerald
You could create a custom hook called useFetchthat will implement the useEffecthook.
您可以创建一个名为的自定义钩子useFetch来实现该useEffect钩子。
By passing an empty array as the second argument to the useEffecthook will trigger the request on componentDidMount.
通过将一个空数组作为第二个参数传递给useEffect钩子将触发对 的请求componentDidMount。
Here is a demo in code sandbox.
See code below.
请参阅下面的代码。
import React, { useState, useEffect } from 'react';
const useFetch = (url) => {
const [data, setData] = useState(null);
// empty array as second argument equivalent to componentDidMount
useEffect(() => {
async function fetchData() {
const response = await fetch(url);
const json = await response.json();
setData(json);
}
fetchData();
}, [url]);
return data;
};
const App = () => {
const URL = 'http://www.example.json';
const result = useFetch(URL);
return (
<div>
{JSON.stringify(result)}
</div>
);
}
回答by SakoBu
Works just fine... Here you go:
工作得很好......给你:
import React, { useState, useEffect } from 'react';
const useFetch = url => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const fetchUser = async () => {
const response = await fetch(url);
const data = await response.json();
const [user] = data.results;
setData(user);
setLoading(false);
};
useEffect(() => {
fetchUser();
}, []);
return { data, loading };
};
const App = () => {
const { data, loading } = useFetch('https://api.randomuser.me/');
return (
<div className="App">
{loading ? (
<div>Loading...</div>
) : (
<React.Fragment>
<div className="name">
{data.name.first} {data.name.last}
</div>
<img className="cropper" src={data.picture.large} alt="avatar" />
</React.Fragment>
)}
</div>
);
};
Live Demo:
现场演示:
Edit
编辑
Updated based on version change (thanks @mgol for bringing it to my attention in the comments).
根据版本更改更新(感谢@mgol 在评论中引起我的注意)。
回答by horyd
Great answers so far, but I'll add a custom hook for when you want to trigger a request, because you can do that too.
到目前为止很好的答案,但我会在你想要触发请求时添加一个自定义钩子,因为你也可以这样做。
function useTriggerableEndpoint(fn) {
const [res, setRes] = useState({ data: null, error: null, loading: null });
const [req, setReq] = useState();
useEffect(
async () => {
if (!req) return;
try {
setRes({ data: null, error: null, loading: true });
const { data } = await axios(req);
setRes({ data, error: null, loading: false });
} catch (error) {
setRes({ data: null, error, loading: false });
}
},
[req]
);
return [res, (...args) => setReq(fn(...args))];
}
You can create a function using this hook for a specific API method like so if you wish, but be aware that this abstraction isn't strictly required and can be quite dangerous (a loose function with a hook is not a good idea in case it is used outside of the context of a React component function).
如果您愿意,您可以使用此钩子为特定的 API 方法创建一个函数,但请注意,此抽象不是严格必需的,并且可能非常危险(带有钩子的松散函数不是一个好主意,以防万一在 React 组件函数的上下文之外使用)。
const todosApi = "https://jsonplaceholder.typicode.com/todos";
function postTodoEndpoint() {
return useTriggerableEndpoint(data => ({
url: todosApi,
method: "POST",
data
}));
}
Finally, from within your function component
最后,从您的功能组件中
const [newTodo, postNewTodo] = postTodoEndpoint();
function createTodo(title, body, userId) {
postNewTodo({
title,
body,
userId
});
}
And then just point createTodoto an onSubmitor onClickhandler. newTodowill have your data, loading and error statuses. Sandbox code right here.
然后只需指向createTodo一个onSubmit或onClick处理程序。newTodo将拥有您的数据、加载和错误状态。沙盒代码就在这里。
回答by Alex Cory
use-httpis a little react useFetch hook used like: https://use-http.com
use-http是一个小小的反应 useFetch 钩子,使用如下:https://use-http.com
import useFetch from 'use-http'
function Todos() {
const [todos, setTodos] = useState([])
const { request, response } = useFetch('https://example.com')
// componentDidMount
useEffect(() => { initializeTodos() }, [])
async function initializeTodos() {
const initialTodos = await request.get('/todos')
if (response.ok) setTodos(initialTodos)
}
async function addTodo() {
const newTodo = await request.post('/todos', {
title: 'no way',
})
if (response.ok) setTodos([...todos, newTodo])
}
return (
<>
<button onClick={addTodo}>Add Todo</button>
{request.error && 'Error!'}
{request.loading && 'Loading...'}
{todos.map(todo => (
<div key={todo.id}>{todo.title}</div>
)}
</>
)
}
or, if you don't want to manage the state yourself, you can do
或者,如果你不想自己管理状态,你可以这样做
function Todos() {
// the dependency array at the end means `onMount` (GET by default)
const { loading, error, data } = useFetch('/todos', [])
return (
<>
{error && 'Error!'}
{loading && 'Loading...'}
{data && data.map(todo => (
<div key={todo.id}>{todo.title}</div>
)}
</>
)
}
Live Demo
现场演示
回答by Matheus Schettino
I'd recommend you to use react-request-hookas it covers a lot of use cases (multiple request at same time, cancelable requests on unmounting and managed request states). It is written in typescript, so you can take advantage of this if your project uses typescript as well, and if it doesn't, depending on your IDE you might see the type hints, and the library also provides some helpers to allow you to safely type the payload that you expect as result from a request.
我建议您使用react-request-hook,因为它涵盖了很多用例(同时多个请求,卸载和托管请求状态的可取消请求)。它是用打字稿编写的,因此如果您的项目也使用打字稿,您可以利用这一点,如果没有,根据您的 IDE,您可能会看到类型提示,并且该库还提供了一些帮助程序以允许您安全地键入您期望作为请求结果的有效负载。
It's well tested (100% code coverage) and you might use it simple as that:
它经过良好测试(100% 代码覆盖率),您可以简单地使用它:
function UserProfile(props) {
const [user, getUser] = useResource((id) => {
url: `/user/${id}`,
method: 'GET'
})
useEffect(() => getUser(props.userId), []);
if (user.isLoading) return <Spinner />;
return (
<User
name={user.data.name}
age={user.data.age}
email={user.data.email}
>
)
}
Author disclaimer: We've been using this implementation in production. There's a bunch of hooks to deal with promises but there are also edge cases not being covered or not enough test implemented. react-request-hook is battle tested even before its official release. Its main goal is to be well tested and safe to use as we're dealing with one of the most critical aspects of our apps.
作者免责声明:我们一直在生产中使用此实现。有一堆钩子来处理承诺,但也有一些边缘情况没有被覆盖或没有足够的测试实现。react-request-hook 甚至在正式发布之前就经过了实战测试。它的主要目标是在我们处理应用程序最关键的方面之一时经过良好测试和安全使用。
回答by Krasimir
Here's something which I think will work:
这是我认为会起作用的东西:
import React, { useState, useEffect } from 'react';
const App = () => {
const URL = 'http://api.com';
const [data, setData] = useState({})
useEffect(async () => {
const resp = await fetch(URL);
const data = await resp.json();
setData(data);
}, []);
return (
<div>
{ data.something ? data.something : 'still loading' }
</div>
)
}
There are couple of important bits:
有几个重要的位:
- The function that you pass to
useEffectacts as acomponentDidMountwhich means that it may be executed many times. That's why we are adding an empty array as a second argument, which means "This effect has no dependencies, so run it only once". - Your
Appcomponent still renders something even tho the data is not here yet. So you have to handle the case where the data is not loaded but the component is rendered. There's no change in that by the way. We are doing that even now.
- 您传递给的函数
useEffect充当 acomponentDidMount这意味着它可能会被执行多次。这就是我们添加一个空数组作为第二个参数的原因,这意味着“这个效果没有依赖关系,所以只运行一次”。 App即使数据还不在这里,您的组件仍然会呈现一些东西。因此,您必须处理未加载数据但已呈现组件的情况。顺便说一下,这没有任何变化。我们现在也在这样做。
回答by Yangshun Tay
Traditionally, you would write the Ajax call in the componentDidMountlifecycle of class components and use setStateto display the returned data when the request has returned.
传统上,您会在componentDidMount类组件的生命周期中编写 Ajax 调用,并用于setState在请求返回时显示返回的数据。
With hooks, you would use useEffectand passing in an empty array as the second argument to make the callback run once on mount of the component.
使用钩子,您将使用useEffect并传入一个空数组作为第二个参数,以使回调在组件安装时运行一次。
Here's an example which fetches a random user profile from an API and renders the name.
这是一个从 API 获取随机用户配置文件并呈现名称的示例。
function AjaxExample() {
const [user, setUser] = React.useState(null);
React.useEffect(() => {
fetch('https://randomuser.me/api/')
.then(results => results.json())
.then(data => {
setUser(data.results[0]);
});
}, []); // Pass empty array to only run once on mount.
return <div>
{user ? user.name.first : 'Loading...'}
</div>;
}
ReactDOM.render(<AjaxExample/>, document.getElementById('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>
回答by u10051458
I find many wrong usages of useEffectin the answers above.
我useEffect在上面的答案中发现了许多错误的用法。
An async function shouldn't be passed into useEffect.
不应将异步函数传入useEffect.
Let's see the signature of useEffect:
让我们看看签名useEffect:
useEffect(didUpdate, inputs);
You can do side effects in didUpdatefunction, and return a dispose function. The dispose function is very important, you can use that function to cancel a request, clear a timer etc.
您可以在didUpdate函数中执行副作用,并返回一个处理函数。dispose 函数非常重要,您可以使用该函数取消请求、清除计时器等。
Any async function will return a promise, but not a function, so the dispose function actually takes no effects.
任何 async 函数都会返回一个 promise,但不会返回一个函数,因此 dispose 函数实际上不起作用。
So pass in an async function absolutely can handle your side effects, but is an anti-pattern of Hooks API.
所以传入一个异步函数绝对可以处理你的副作用,但它是 Hooks API 的反模式。


