关于使用`Date.now()`初始化`useState`的问题

时间:2020-06-18 20:55:22

标签: javascript reactjs react-hooks

我正在使用API​​从Firestore检索最新帖子。 API就是这样

function loadFeedPosts(
  createdAtMax,
  limit
) {
  return db
    .collection("posts")
    .orderBy("createdAt", "desc")
    .where("createdAt", "<", createdAtMax)
    .limit(limit)
    .get()
    .then(getDocsFromSnapshot)
}

createdAtMax是我们需要指定才能检索帖子的时间。

我有一个Feed组件。看起来像这样。



function Feed() {
  const [posts, setPosts] = useState([])
  const [currentTime, setCurrentTime] = useState(Date.now())
  const [limit, setLimit] = useState(3)

  useEffect(() => {
    loadFeedPosts(currentTime, limit).then(posts => {
      setPosts(posts)
    })
  }, [currentTime, limit])

  return (
    <div className="Feed">
      <div className="Feed_button_wrapper">
        <button className="Feed_new_posts_button icon_button">
          View 3 New Posts
        </button>
      </div>

      {posts.map(post => (
        <FeedPost post={post} />
      ))}

      <div className="Feed_button_wrapper">
        <button
          className="Feed_new_posts_button icon_button"
          onClick={() => {
            setLimit(limit + 3)
          }}
        >
          View More
        </button>
      </div>
    </div>
  )
}

因此,当人们单击View More按钮时,它将再检索3个帖子。

我的问题是,由于单击View More按钮会触发重新渲染,因此我假设const [currentTime, setCurrentTime] = useState(Date.now())行将再次运行,是否Date.now()用作初始值currentTime的每次重新渲染都需要重新评估?

我自己通过注销currentTime进行了测试,似乎为每个渲染器进行更新。根据React文档https://reactjs.org/docs/hooks-reference.html#lazy-initial-state,我认为只有在使用惰性初始状态时,initialState才被计算一次。但是这里我没有使用惰性初始状态,为什么每次重新渲染组件时都不会计算出来?

尽管 currentTime的初始状态的预期行为在每次重新渲染时都保持不变,但令我困惑的是为什么没有为每个重新渲染而重新计算它重新渲染,因为我没有使用惰性初始状态

2 个答案:

答案 0 :(得分:2)

使用useState仅提供初始值,因为关于useState钩子的doc表示:

作为参数传递给useState的是什么?唯一的论点 useState()挂钩是初始状态。

我们进行延迟初始化的原因是,在后续渲染中initialValue将被忽略,如果这是昂贵的计算结果,则可能要避免重新执行它。

const [value, setValue] = useState(expensiveComputation());
// expensiveComputation will be executed at each render and the result disregarded

const [value, setValue] = useState(() => expensiveComputation());
// expensiveComputation will be executed only at the first render

答案 1 :(得分:2)

useState()使用mount初始化状态,它在第一次渲染之前运行。

来自doc

初始渲染期间,返回的状态(状态)与 作为第一个参数(initialState)传递的值。

我们为什么需要惰性初始状态?

让我们说我们是通过一些高复杂度函数得出初始状态的。让我们尝试不使用惰性状态方法:

const A = () => {
  const [a, setA] = useState("blabla")
  const processedA = processA(a) // Wait! this will run on every render!, 
  // so i need to find a way to prevent to be processed after first render.

  return ...
}

要实现仅运行一次的功能,我应该使用useRef跟踪渲染:

const A = () => {
  const [a, setA] = useState("blabla")
  let processedA

  const willMount = useRef(true);
  if (willMount.current) {
    processedA = processA(a)
  }

  useEffect(() => {
    willMount.current = false;
  }), []);

 return ...
}

多么丑陋的方法,不是吗?

另一种方法可以使用useEffect,但是这次它将在安装后的第二个渲染上工作。所以我将有不必要的第一个渲染:

const A = () => {
  const [a, setA] = useState("blabla")

  useEffect(()=>{
    const processedA = processA(a)
    setA(processedA)
  }, [a])

  return ...
}