状态变量变化导致无限渲染循环

State variable change causes an infinte render loop

我正在尝试使用 React 创建评论部分。该组件使用外部连接提取一个大型数据集中的所有评论和对每个评论的回复,然后将结果复制到两个单独的数组(评论数组和回复数组)

但是,当我尝试将评论数组设置为状态变量时,组件会无限地重新呈现自身。

我在出现问题的地方添加了评论。取消下面一行的注释,程序可以正常运行,但是map函数没有任何显示

import React, {useState, useEffect} from 'react'
import Axios from 'axios';
import {Form, Button} from 'react-bootstrap';
import Comment from './Comment';
import { render } from 'react-dom';

function Thread(props) { 
    const {threadID} = props;
    const [commentBody, setCommentBody] = useState('');
    const [replyArray, setReplyArray] = useState([]);
    const [commentArray, setCommentArray] = useState([]);
    const [comments, setComments] = useState([]);
    let commentResponse = [];
      useEffect(() => {
      Axios.get(`http://localhost:3001/api/selectcomments/${threadID}`).then((res) => {
      commentResponse = res.data;
    });
  }, [threadID]);

let tempReplies = [];
let tempComments = [];
for(let i = 0 ; i < commentResponse.length; i++)
  {
    tempComments.push({body: comments[i].body, commentID: comments[i].commentID})
    tempReplies.push({replyBody: comments[i].replyBody, commentID: comments[i].commentID})
  }

  let filteredArray = [...new Map(tempComments.map(x => [x['commentID'], x])).values()]
  console.log("splitArray called")


  //CAUSES INFINITE RENDER LOOP
  setCommentArray(filteredArray);

 return (
<section className="comment-wrapper">
      <div className="comment-section">
        <h2>Comments</h2>
        <Form>
          <Form.Control
            as="textarea"
            rows={3}
            placeholder="Leave a Comment"
            onChange={(val) => {
              setCommentBody(val);
            }}
          />
        </Form>
        <Button
          // all elements in the comment section have a default margin of 1rem, but this looks strange when applied to this button
          style={{ "margin-top": "0rem" }}
          type="submit"
          variant="primary"
        >
          Post
        </Button>
        
        {
        commentArray.map((data) => {
          
          console.log('map function for thread fired');
          console.log(commentArray)

          const {commentID, body} = data;
          
          const replies = replyArray.filter(x => x.commentID == commentID)
          return (
            <>
              <Comment username="User1" body={body} commentId = {commentID}/>

              {
              
              
              replies.map((replyData)=>{ 
              if(!(replyData.replyBody == null))
              {
              return(
                
              <div className="reply">
              <h3>Username</h3>
              <p>{replyData.replyBody}</p>
              </div>
              )
              }
              
              }
              )}
              
              
            </>
          );
        })}
      </div>
    </section>

) }

导出默认线程

您遇到了一个问题,因为每次您的组件都无条件地设置状态 re-renders;导致 yet-another re-render.

在这种情况下,您需要退后一步,想想 什么时候 您确实需要 UI 重绘自己。在这种情况下,就目前的代码而言,它非常简单——当一些数据从服务器返回时 API.

您在 useEffectAxios.get 调用的 then() 中已经得到了一些东西 运行。这里其实最理想的地方是在设置状态之前做所有数组slicing-and-dicing,这会导致re-draw:

useEffect(() => {
    Axios.get(
      `http://dummy.restapiexample.com/api/v1/employee/${threadID}`
    ).then((res) => {
      commentResponse = res.data;
      let tempReplies = [];
      let tempComments = [];
      for (let i = 0; i < commentResponse.length; i++) {
        tempComments.push({
          body: comments[i].body,
          commentID: comments[i].commentID
        });
        tempReplies.push({
          replyBody: comments[i].replyBody,
          commentID: comments[i].commentID
        });
      }

      let filteredArray = [
        ...new Map(tempComments.map((x) => [x["commentID"], x])).values()
      ];
      console.log("splitArray called");

      // This should now work fine - no infinite looping
      setCommentArray(filteredArray);
    });
  }, [threadID]);