首页 > 解决方案 > 为什么我需要将函数放在 setState 方法中才能工作?

问题描述

当一个套接字从服务器端发出一个事件时,应用程序由于某种原因重新加载并且帖子被清空。但是当我在 setPosts 中定义函数时,它可以完美运行。为什么是这样?

const App = () => {
  let [user, setUser] = useState(null)
  let [posts, setPosts] = useState({})
  console.log('app')

  useEffect(() => {
    console.log('use effect')

    socket.on('post', (post) => {


      // THIS DOES NOT WORK:
      // let newPosts = { ...posts }
      // newPosts[post._id] = post
      // setPosts(newPosts)

      //THIS WORKS
      setPosts((posts) => {
        let newPosts = { ...posts }
        newPosts[post._id] = post
        return newPosts
      })
    })



    async function getUser() {
      let user = await actions.getUser()
      if (user) {
        setUser(user?.data)
      }
    }

    getUser()

    actions
      .getAllPosts()
      .then((res) => {
        console.log('WE GOT ALL POSTSTFOM API', res.data)
        const postsById = {}
        for (let post of res.data) {
          postsById[post._id] = post
        }
        console.log('wired')
        setPosts(postsById)
        //filterPosts(res.data)
      })
      .catch((err) => console.error(err))

    return () => {
      socket.off('post')
    }
  }, [])

标签: reactjssocket.io

解决方案


这就是附件在 javascript 中的工作方式。当您使用非功能性状态更新时,您是在实例化回调的渲染周期中引用posts状态值 ( {}),即在挂载时运行效果回调时的初始渲染(注意空依赖数组)。posts这是状态价值的陈旧外壳。

使用功能状态更新时,您正在访问和更新前一个状态,而不是前一个渲染周期(或外壳)的状态。


推荐阅读