React Hooks - 发出Ajax请求

pet*_*gan 11 javascript reactjs react-hooks

我刚刚开始使用React钩子,我想知道AJAX请求应该如何看待?

我尝试了很多尝试,但是无法让它工作,也不知道实现它的最佳方法.以下是我最近的尝试:

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>
    )
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*ald 26

您可以创建一个名为的自定义钩子useFetch来实现useEffect钩子.

通过将空数组作为第二个参数传递给useEffect钩子将触发请求componentDidMount.

这是代码沙箱中的演示.

见下面的代码.

import React, { useState, useEffect } from 'react';

const useFetch = (url) => {
  const [data, updateData] = useState(undefined);

  // empty array as second argument equivalent to componentDidMount
  useEffect(() => {
    async function fetchData() {
      const response = await fetch(url);
      const json = await response.json();
      updateData(json);
    }
    fetchData();
  }, [url]);

  return data;
};

const App = () => {
    const URL = 'http://www.example.json';
    const result = useFetch(URL);

    return (
      <div>
        {JSON.stringify(result)}
      </div>
    );
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我想在另一个组件中重用相同的响应怎么办?即使 URL 相同,每次调用 `useFetch` 都会重新获取数据。无法在 2 个组件之间共享相同的 `useState`。 (2认同)

Sak*_*oBu 7

效果很好...在这里,您可以:

编辑:根据版本更改进行更新(感谢@mgol在评论中引起我的注意...

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>
  );
};
Run Code Online (Sandbox Code Playgroud)

现场演示:

编辑x908rkw8yq


hor*_*ryd 7

到目前为止很棒的答案,但是我会在你想要触发请求的时候添加一个自定义钩子,因为你也可以这样做.

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))];
}
Run Code Online (Sandbox Code Playgroud)

你可以使用这个钩子为特定的API方法创建一个函数,如果你愿意的话,但是要注意这个抽象并不是严格要求的,并且可能非常危险(带有钩子的松散函数不是一个好主意,如果它在React组件函数的上下文之外使用).

const todosApi = "https://jsonplaceholder.typicode.com/todos";

function postTodoEndpoint() {
  return useTriggerableEndpoint(data => ({
    url: todosApi,
    method: "POST",
    data
  }));
}
Run Code Online (Sandbox Code Playgroud)

最后,从您的功能组件中

const [newTodo, postNewTodo] = postTodoEndpoint();

function createTodo(title, body, userId) {
  postNewTodo({
    title,
    body,
    userId
  });
}
Run Code Online (Sandbox Code Playgroud)

然后只指向createTodo一个onSubmitonClick处理程序.newTodo将拥有您的数据,加载和错误状态.沙盒代码就在这里.

  • 您在 `useEffect` 中调用 ajax 请求的方式是错误的。根据文档,`useEffect` 函数必须是纯函数,因为它也会自动进行清理。所以,正确的方法是:`useEffect(() =&gt; { fetchData() })` 其中 fetchData 可以写成:`async function fetchData() { ...}`。 (2认同)

Ale*_*ory 5

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>
      )}
    </>
  )
}
Run Code Online (Sandbox Code Playgroud)

或者,如果你不想自己管理状态,你可以这样做

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>
      )}
    </>
  )
}
Run Code Online (Sandbox Code Playgroud)

现场演示

编辑基本示例