首页 > 解决方案 > useEffect 陷入无限循环

问题描述

我得到一个无限循环,我知道问题是因为我在 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>
)

}

标签: reactjsaxiosinfinite-loopuse-effectuse-state

解决方案


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

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

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


推荐阅读