React useState 在通过传播引用克隆数组时不会重新渲染
React useState is not re-rendering while it is referring cloned array by spreading
我正在尝试对数组进行排序并通过 useState 挂钩立即反映其排序结果。
我已经知道 React 正在通过 Object.is()
检测其状态变化,因此在使用 useState
之前尝试传播数组,如下所示;
const [reviews, setReviews] = useState([...book.reviews]);
useEffect(() => {
const sortedReviews = [...reviews]
.sort((review1: IReview, review2: IReview) =>
sortBy(review1, review2, sortRule));
setReviews([...sortedReviews])
}, [sortRule])
排序后,我检查了变量 sortedReviews
的值,它按预期排序,但 React 没有重新渲染页面,所以这个排序没有反映到 UI.
我已经搜索了解决方案,似乎很多人都可以通过在调用 useState
之前将数组传播到来解决问题,就像这个堆栈溢出解释的那样:.
但是,在我这边它不起作用。任何帮助将不胜感激。谢谢!
[已添加]
我的渲染部分如下;
<>
{
sortedReviews
.map((review: IReview) => (
<ReviewBlock id={review.id}
review={review}
targetBook={book}
setTargetBook={setBook}/>
))
}
</>
当组件不重新渲染时,几乎总是由于状态突变。在这里,您在 reviews
上调用变异操作 .sort
。在你改变它之前,你需要传播数组。
useEffect(() => {
const sortedReviews = [...reviews].sort((review1: IReview, review2: IReview) =>
sortBy(review1, review2, sortRule)
);
setReviews(sortedReviews);
}, [sortRule]);
但是这里还有其他问题。 reviews
不是 useEffect 的依赖项,因此我们希望使用 setReviews
回调,例如 setReviews(current => [...current].sort(...
.
一般来说,排序数据作为 useMemo
比 useState
更有意义。 sortRule
是一个状态,sortedReviews
是从它派生的。
您调用 sortBy
作为比较函数的方式感觉有点不对劲。也许这只是一个令人困惑的名字?
此外,如果 book
被正确输入为 {reviews: IReview[]}
,则您不需要在回调中包含类型 IReview
。
如果您包含 sortBy
函数和 sortRule
变量,那么我可以提供更多帮助。但这是我想出的。
import React, { useState, useMemo } from "react";
type IReview = {
rating: number;
}
type Book = {
reviews: IReview[]
}
type SortRule = string; // just a placeholder - what is this really?
declare function sortBy(a: IReview, b: IReview, rule: SortRule): number;
const MyComponent = ({book}: {book: Book}) => {
const [sortRule, setSortRule] = useState("");
const reviews = book.reviews;
const sortedReviews = useMemo( () => {
return [...reviews].sort((review1, review2) =>
sortBy(review1, review2, sortRule)
);
}, [sortRule, reviews]);
...
}
有时我也遇到这个问题,在我的情况下,我只是“强制”渲染调用回调。
第一个解法:
const [reviews, setReviews] = useState([...book.reviews]);
useEffect(() => {
const sortedReviews = [...reviews]
.sort((review1: IReview, review2: IReview) =>
sortBy(review1, review2, sortRule));
setReviews(()=> [...sortedReviews]) // <-- Here
}, [sortRule])
第二种解法:
可以使用useRef实时获取数据,见下:
const [reviews, setReviews] = useState([...book.reviews]);
const reviewsRef = useRef();
useEffect(() => {
const sortedReviews = [...reviews]
.sort((review1: IReview, review2: IReview) =>
sortBy(review1, review2, sortRule));
setReviewRef([...sortedReviews])
}, [sortRule])
function setReviewRef(data){
setReview(data);
reviewsRef.current = data;
}
所以,改为使用状态 评论 使用 reviewsRef.current 作为数组
希望你能解决这个问题!
我正在尝试对数组进行排序并通过 useState 挂钩立即反映其排序结果。
我已经知道 React 正在通过 Object.is()
检测其状态变化,因此在使用 useState
之前尝试传播数组,如下所示;
const [reviews, setReviews] = useState([...book.reviews]);
useEffect(() => {
const sortedReviews = [...reviews]
.sort((review1: IReview, review2: IReview) =>
sortBy(review1, review2, sortRule));
setReviews([...sortedReviews])
}, [sortRule])
排序后,我检查了变量 sortedReviews
的值,它按预期排序,但 React 没有重新渲染页面,所以这个排序没有反映到 UI.
我已经搜索了解决方案,似乎很多人都可以通过在调用 useState
之前将数组传播到来解决问题,就像这个堆栈溢出解释的那样:
但是,在我这边它不起作用。任何帮助将不胜感激。谢谢!
[已添加] 我的渲染部分如下;
<>
{
sortedReviews
.map((review: IReview) => (
<ReviewBlock id={review.id}
review={review}
targetBook={book}
setTargetBook={setBook}/>
))
}
</>
当组件不重新渲染时,几乎总是由于状态突变。在这里,您在 reviews
上调用变异操作 .sort
。在你改变它之前,你需要传播数组。
useEffect(() => {
const sortedReviews = [...reviews].sort((review1: IReview, review2: IReview) =>
sortBy(review1, review2, sortRule)
);
setReviews(sortedReviews);
}, [sortRule]);
但是这里还有其他问题。 reviews
不是 useEffect 的依赖项,因此我们希望使用 setReviews
回调,例如 setReviews(current => [...current].sort(...
.
一般来说,排序数据作为 useMemo
比 useState
更有意义。 sortRule
是一个状态,sortedReviews
是从它派生的。
您调用 sortBy
作为比较函数的方式感觉有点不对劲。也许这只是一个令人困惑的名字?
此外,如果 book
被正确输入为 {reviews: IReview[]}
,则您不需要在回调中包含类型 IReview
。
如果您包含 sortBy
函数和 sortRule
变量,那么我可以提供更多帮助。但这是我想出的。
import React, { useState, useMemo } from "react";
type IReview = {
rating: number;
}
type Book = {
reviews: IReview[]
}
type SortRule = string; // just a placeholder - what is this really?
declare function sortBy(a: IReview, b: IReview, rule: SortRule): number;
const MyComponent = ({book}: {book: Book}) => {
const [sortRule, setSortRule] = useState("");
const reviews = book.reviews;
const sortedReviews = useMemo( () => {
return [...reviews].sort((review1, review2) =>
sortBy(review1, review2, sortRule)
);
}, [sortRule, reviews]);
...
}
有时我也遇到这个问题,在我的情况下,我只是“强制”渲染调用回调。
第一个解法:
const [reviews, setReviews] = useState([...book.reviews]);
useEffect(() => {
const sortedReviews = [...reviews]
.sort((review1: IReview, review2: IReview) =>
sortBy(review1, review2, sortRule));
setReviews(()=> [...sortedReviews]) // <-- Here
}, [sortRule])
第二种解法: 可以使用useRef实时获取数据,见下:
const [reviews, setReviews] = useState([...book.reviews]);
const reviewsRef = useRef();
useEffect(() => {
const sortedReviews = [...reviews]
.sort((review1: IReview, review2: IReview) =>
sortBy(review1, review2, sortRule));
setReviewRef([...sortedReviews])
}, [sortRule])
function setReviewRef(data){
setReview(data);
reviewsRef.current = data;
}
所以,改为使用状态 评论 使用 reviewsRef.current 作为数组
希望你能解决这个问题!