我正在使用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
的初始状态的预期行为在每次重新渲染时都保持不变,但令我困惑的是为什么没有为每个重新渲染而重新计算它重新渲染,因为我没有使用惰性初始状态
答案 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 ...
}