当前位置: 首页 > 知识库问答 >
问题:

React useState在通过扩展引用克隆数组时未重新呈现

艾安和
2023-03-14

我试图排序数组,并反映其排序结果立即使用状态钩子。我已经新的反应是检测其状态变化的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])

排序后,我检查了变量sorted评论的值,它按预期进行了排序,但反应并没有重新渲染页面,所以这种排序没有反映到用户界面。

我已经搜索了解决方案,似乎很多人可以通过在调用useState之前传播一个数组来解决这个问题,就像这个堆栈溢出解释的那样:为什么useState没有触发重新渲染?。任何帮助将非常感谢。谢谢你!

[新增]我的渲染部分如下:;

    <>
        {
            sortedReviews
                .map((review: IReview) => (
                    <ReviewBlock id={review.id}
                                 review={review}
                                 targetBook={book}
                                 setTargetBook={setBook}/>
                ))
        }
    </>

共有2个答案

韦阳辉
2023-03-14

当组件不重新渲染时,几乎总是由于状态的变化。这里您正在调用审阅上的变异操作.sort。在变异之前,您需要传播数组。

useEffect(() => {
  const sortedReviews = [...reviews].sort((review1: IReview, review2: IReview) =>
    sortBy(review1, review2, sortRule)
  );

  setReviews(sortedReviews);
}, [sortRule]);

但这里还有其他问题reviews不是useEffect的依赖项,因此我们希望使用setReviews回调,如setReviews(当前=

通常,排序数据作为usemo比作为useState更有意义。sortRule是一种状态,sortedReviews就是从中派生出来的。

调用sortBy作为比较函数的方式感觉有点不对劲。也许只是个让人困惑的名字?

此外,如果书籍正确键入为{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]);
...
}

打字游戏链接

百里朝
2023-03-14

有时我也会遇到这个问题,在我的例子中,我只是“强制”渲染调用回调。

第一个解决方案:

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作为u数组

我希望你能解决这个问题!

 类似资料:
  • 为了在处理JavaScript对象时通过另一个对象继承一个对象的属性,我经常看到使用,其目的是创建一个具有另一个对象属性的对象,然后对其进行扩展。 为什么我们不能只使用与扩展对象更相关的 ? 请告诉我这两者之间的区别,以及为什么我们不能而不是这是一个昂贵的操作。

  • 我想制作一份扩展的副本,作为我自己扩展的基础。我如何克隆一个TYPO3扩展,以同样的行为开始我自己的扩展。我必须更改哪些文件和参数?

  • 我是新来的反应。作为一个学习练习,我正在构建一个国际象棋应用程序 我想根据父级中的状态更改子级的DOM。当前,在父级组件的状态变化时,子级组件没有变化。 PS:请忽略任何语法错误。这段代码是实际代码的精简。如果你想看完整的代码,请看这里

  • 问题内容: 我有ng-table的页面,可以很好地处理初始数据。我有一个选择框,该框根据选择的选项发送服务器请求,然后Iam将新数据获取为angular,但未使用ng- table更新。 这是我的看法: 我的控制器: 问题答案: $scope.$watch(‘result’, function () { $scope.tableParams.settings().$scope = $scope;

  • 问题内容: 假设我已经定义了这样的协议: 现在,我想扩展并采用该协议。 但是下面的代码: 由于错误而无效 错误:必须在非专用泛型类型“ Array”上声明受约束的扩展,并使用“ where”子句指定约束 我发现类似的问题,但建议的解决方案是使用,但在这种情况下它会导致错误: 错误:协议“ CollectionType”只能用作一般约束,因为它具有“自我”或相关类型要求 有什么解决办法吗? 编辑:

  • 问题内容: 我知道您不能动态扩展普通数组,但这是一种有效的方法吗? 我知道比尝试使用普通数组更好的方法,但是我想首先使用普通数组来解决这个问题。 我的愿望是,它从0 + 1(so 1)开始,在被称为new时,它的大小与相同,然后保持不变,同时再次声明,然后将其复制回新的大小。这对我来说很有意义,但我总是会遇到异常情况? 问题答案: 该方法不会更改OrigArray的值;它所做的只是在其中存储一个克