使用 useEffect 反应 axios 获取请求而不会导致无限循环

Posted

技术标签:

【中文标题】使用 useEffect 反应 axios 获取请求而不会导致无限循环【英文标题】:React axios get request without resulting in infinite loop using useEffect 【发布时间】:2020-10-18 03:24:38 【问题描述】:

我通过这个 axios get 请求得到一个无限循环,但是当我尝试在 useEffect 结束时将消息或 setMessages 作为 [] 内的值时,需要单击 2 次按钮来更新屏幕或它导致错误提示网络资源不足。那我应该放什么呢?

function CommentsPage() 
  const  user  = useAuth0();

  const [query, setQuery] = useState("");
  const [messages, setMessages] = useState([]);

  //fetches data from mongodb for comments
  useEffect(() => 
    fetchComments();
  , [messages]);

  //calls backend to fetch data from the messages collection on mongodb
  async function fetchComments() 
    const response = await axios.get("http://localhost:5000/messages");

    setMessages(response.data);
  

  // handles when a user types in the comment bar
  function handleOnInputChange(event) 
    // current value of what user is typing
    const  value  = event.target;

    setQuery(value);
  

  // handles when a user posts a comment
  function postComment(comment, user) 
    const newMessage = 
      username: user.name,
      content: comment,
    ;

    // calls backend to send a post request to insert a new document into the collection
    axios
      .post("http://localhost:5000/messages", newMessage)
      .then((res) => console.log(res.data));

    setQuery("");
    fetchComments();
  

  // handles when a user deletes a comment
  function deleteComment(id) 
    axios
      .delete("http://localhost:5000/messages/delete/" + id)
      .then((res) => console.log(res.data));

    fetchComments();

    setMessages(messages.filter((message) => message.id !== id));
  

  // handles when a user updates a comment
  function updateComment(id) 
    // calls a pop up that allows user to input their new comment
    const editedContent = prompt("please enter new message");

    const newMessage = 
      username: user.name,
      content: editedContent,
    ;

    axios
      .put("http://localhost:5000/messages/update/" + id, newMessage)
      .then((res) => console.log(res.data));

    fetchComments();
  

  console.log(messages);

  return (
    <Container>
      <CommentsContainer>
        messages.length ? (
          messages.map((message) => 
            /* if the usernames match then a user comment is returned
            otherwise an other comment will be returned */
            return message.username === user.name ? (
              <UserComment
                key=message._id
                username=message.username
                content=message.content
                deleteComment=deleteComment
                id=message._id
                updateComment=updateComment
              />
            ) : (
              <OtherComment
                key=message._id
                username=message.username
                content=message.content
              />
            );
          )
        ) : (
          <div>There are no comments. Make one!</div>
        )
      </CommentsContainer>
      <CommentBarStyle htmlFor="search-input">
        <input
          name="commentBar"
          type="text"
          value=query
          id="search-input"
          placeholder="Write a comment..."
          onChange=handleOnInputChange
        />
        <AddIcon
          className="fas fa-plus"
          onClick=() => postComment(query, user)
        />
      </CommentBarStyle>
    </Container>
  );


export default CommentsPage;

【问题讨论】:

【参考方案1】:

您的 useEffect 将在每次消息状态发生变化时运行。像这样改变你的 useEffect:

useEffect(() => 
    fetchComments();
,[null]);

【讨论】:

对不起,也许我应该更具体一些,如果我将空数组传递给 useEffect,那么每当我尝试制作、编辑或删除评论时,我都需要进入另一个页面在它更新之前,当我希望它在那里更新时。那么我怎样才能像这样更新页面呢? 只需将 fetchComments() 放入您所有的 axios 中即可。然后回调它会解决您的问题。 ` axios.post('url').then(()=> fetchComments() ) `【参考方案2】:

您正在更新 fetchComments 中的“消息”状态...所以每次更新此状态时都会调用您的 useEffect,因为它具有消息作为依赖项。

  useEffect(() => 
    fetchComments();
  , [messages]);

  //calls backend to fetch data from the messages collection on mongodb
  async function fetchComments() 
    const response = await axios.get("http://localhost:5000/messages");

    setMessages(response.data);
  

试试这个:

useEffect(() => 
  fetchComments();
, []);

如果您这样做,您的组件将在挂载阶段调用 fetchComments,而不是在每次消息状态更改时调用它。

【讨论】:

对不起,也许我应该更具体一些,如果我将空数组传递给 useEffect,那么每当我尝试制作、编辑或删除评论时,我都需要进入另一个页面在它更新之前,当我希望它在那里更新时。那么我怎样才能像这样更新页面呢? 你能把你的代码放在一个沙箱里吗? 感谢您查看它的建议,但我按照 Adeel 的建议做了,它最终工作了

以上是关于使用 useEffect 反应 axios 获取请求而不会导致无限循环的主要内容,如果未能解决你的问题,请参考以下文章

如何在useEffect中使用axios请求测试反应组件?

为啥我的 axios 使用 React.useEffect 一遍又一遍地从 Rails 后端获取调用?

在 useEffect 挂钩中使用 axios 取消令牌时如何修复失败的测试

使用 axios 获取数据后 React useEffect 返回空数组

Axios 没有使用 useEffect() (React Js) [重复]

redux中如何使用axios获取api项?