【问题标题】:useEffect gets stuck in an infinite loopuseEffect 陷入无限循环
【发布时间】:2021-02-15 14:44:01
【问题描述】:

我得到了一个无限循环,我知道问题是因为我在 useEffect 函数中将“posts”和“setPost”作为第二个参数放在括号中,但我需要在添加时渲染页面新帖子,所以帖子必须放在括号中。

function Home() {
   const {userData, setUserData} = useContext(userContext)
   const [posts, setPost] = useState([])
   const [createPost, setCreatePost] = useState('')
   
   const handleToken = () => {
      localStorage.removeItem('auth-token')
   }

const token = localStorage.getItem("auth-token");

const handleOnSubmit = (e) => {
    e.preventDefault()
    axios.post('http://localhost:5000/posts', {textOfThePost: createPost}, {
        headers: { 'auth-token': token },
    })
    .then((res) => {setCreatePost("")})
}

useEffect(() => {
    axios.get('http://localhost:5000/posts')
    .then(res => {
        setPost(res.data)
    })
}, [posts])

return (
    <div className="home">
        <div style={{display: 'flex', alignItems: 'center'}}>
            <h1>this is the home: Welcome, {userData.username}</h1>
            <Link style={{margin: 10}} to="/home">home</Link>
            <Link style={{margin: 10}} to="/profile">profile</Link>
            <Link style={{margin: 10}} onClick={handleToken} to="/">log out</Link>
        </div>
        <form onSubmit={handleOnSubmit}>
            <input type="text" placeholder="What's happening?" value={createPost} onChange={e => setCreatePost(e.target.value)}/>
            <button type="submit">tweet</button>
        </form>
        <div style={{display: 'flex', flexDirection: 'column'}}>
            {posts.map(post => (
                <div style={{border: '2px solid black', marginBottom: 10, marginRight: 'auto', marginLeft: 'auto', width: 300}} key={post._id}>
                    <div style={{display: 'flex', alignItems: 'center'}}>
                    <Avatar src={post.avatar}/>
                    <span style={{color: 'blue', marginLeft: 10}}>{post.name} <span style={{color: 'grey', fontSize: 11}}>@{post?.username}</span></span><br/>
                    </div>
                    <span>{post.textOfThePost}</span><br/>
                    <span>{moment(post.date).format('lll')}</span>
                </div>
            )).reverse()}
        </div>
    </div>
)

}

【问题讨论】:

  • 请注意,您应该可以在此处使用asyncawait
  • 这个related answer值得一看。
  • posts 不应该在依赖列表中,你没有在你的效果中使用它。最有可能的是,您应该在创建帖子后更新您的状态。

标签: reactjs axios infinite-loop use-effect use-state


【解决方案1】:

你没有在你的效果中使用posts,所以它根本不应该在你的依赖数组中。您的问题的一个解决方案可能是在第一次渲染中获取帖子,仅一次,然后每当您创建帖子时,使用更新 posts 状态的响应。

const posts = [
  { id: "1", text: "foo" },
  { id: "2", text: "bar" },
  { id: "3", text: "baz" }
];

const API = {
  getPosts: () =>
    new Promise((resolve) => setTimeout(() => resolve(posts), 2000)),
  createPost: () =>
    new Promise((resolve) =>
      setTimeout(() => resolve({ id: "3", text: "fizz" }), 1000)
    )
};

function Posts() {
  const [posts, setPosts] = React.useState([]);

  React.useEffect(() => {
    API.getPosts().then(setPosts);
  }, []);

  function handleOnSubmit() {
    API.createPost().then((res) => setPosts((prev) => [...prev, res]));
  }

  return (
    <div>
      <div>
        <button onClick={handleOnSubmit}>Create Post</button>
      </div>
      {!Boolean(posts.length) ? (
        <span>Loading posts...</span>
      ) : (
        posts.map((post) => <div>{post.text}</div>)
      )}
    </div>
  );
}

ReactDOM.render(
  <Posts />,
  document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root" />

不要打扰API 部分,我只是在模仿你的要求。重要的部分是在创建帖子、使用响应和更新状态之后。

【讨论】:

    【解决方案2】:

    这里的问题是useEffect(和类似的钩子)的依赖数组没有使用深度比较(出于性能原因)。

    也就是说,每当您通过 Axios 获取新数据时,res.data 是一个新的 JavaScript 对象,当您将其分配给状态时,效果依赖项将其视为完全更改的对象并再次运行效果,等等。

    最简单的解决方法是使用深度比较 useEffect,例如 https://github.com/kentcdodds/use-deep-compare-effect

    【讨论】:

      猜你喜欢
      • 2021-12-13
      • 2020-05-13
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      • 2022-01-23
      相关资源
      最近更新 更多