首页 > 解决方案 > React 中的渲染和最佳实践

问题描述

我是 React 的初学者,我有一个关于渲染的问题,其中包括我使用 useEfect 来渲染变量中的变化,该变量在 useState 中装饰

以下是声明:

const CardRepo: React.FC<DadosCardRepo> = ({ Nome }) => {

const [nomeRepo, setNomeRepo] = useState(Nome);
const [data, setData] = useState({});
const [languages, setLanguages] = useState<Languages[]>([]);

这是一个组件,它接收一个带有Name的对象,并在nameRepo中设置这个值Name

以下是两种方法:

useEffect(() => {
        getRepo(nomeRepo)
            .then(data => {
                setData(data);
            });
}, [nomeRepo]);

useEffect(() => {
        getLanguages(data['languages_url'])
            .then(data => {
                let total = 0;
                const languagesRef: Languages[] = [];
                Object.keys(data).map((key) => {
                    total += data[key];

                    languagesRef.push({ Nome: key, Porct: data[key] });
                });

                languagesRef.map((language, i, array) => {
                    setLanguages((oldValues) => [...oldValues, { Nome: language.Nome.toLowerCase(), Porct: +((language.Porct * 100) / total).toFixed(2) }]);
                });
            });
}, [data]);

我在更改 nomeRepo 时运行的第一个 useEfect,在此方法中,我向 getRepo 服务发出请求

第二个,当我更改日期时,在此方法中,我向 getLanguages 服务发出请求,并对响应进行处理以用它制作一个列表,在那里我分配语言。

这是清单:

{
  languages.map((el, i) => {
      return (
          <div className="progress-bar" id={el.Nome} key={i} style={{ width: el.Porct + '%' }}></div>
      );
  })
}

我的问题与渲染有关,我知道我只能列出一些东西,如果我在变量“语言”中使用 useEfect,我将在其中分配值并使用变量中的更改再次渲染,否则我不能。

但是当我对代码进行任何更改时,它只呈现更改的位置,但它分配的值与分配的相同,例如:[1,2,3] => [1,2,3,1 ,2,3]。我试图把 setLanguages([]),但它具有相同的行为,我想知道如何解决这个问题,以及以这种方式进行调用和列出是否是一个好习惯。

标签: reactjsreact-hooks

解决方案


首先,有一种不好的做法是从道具创建派生状态。nomeRepo来自 props Nome,你应该尽量避免这种派生状态。您最好删除nomeRepo状态并仅使用Nome.

您的第一次使用效果变为:

useEffect(() => {
        getRepo(Nome)
            .then(data => {
                setData(data);
            });
}, [Nome]);

你第二个useEffectsetState地图内触发了。这将多次触发您的 setState,创建多个重新渲染。最好先准备好你的语言数组,然后调用setState一次。

此外,如果您不使用返回的数组,并且只在每个元素上运行一些脚本,则应该使用forEach而不是。map

需要注意的一件事是,您正在向旧语言添加新语言。我假设语言应该是相关data['languages_url']的值,这样你就不会将旧语言包含到 setLanguages 中。

您可以考虑的一件事是保留您的总值而不是百分比。您可以使用useMemototal存储到变量中,这取决于. 并将您的百分比函数声明到文件夹中并根据需要将其导入。languagesutils

重构第二个 useEffect:

// calculate total value that gets memoized
const totalLangCount = useMemo(() => languages.reduce((total, val) => total + val.count , 0), [languages])

useEffect(() => {
  getLanguages(data['languages_url'])
      .then(data => {
          const languagesRef: Languages[] = [];
          Object.keys(data).forEach((key) => {
              // prepeare your languages properties
              const nome = key.toLowerCase();
              const count = data[key];

              languagesRef.push({ nome, count });
          });

          // avoid multiple setLanguages calls
          setLanguages(languagesRef)
      });
}, [data]);

呈现的语言:

{
  languages.map((el, i) => {
      return (
          //  here we are using array's index as key, but it's best to use some unique key overall instead
          <div className="progress-bar" id={el.nome} key={i} style={{ width: percentage(el.count, total) }}></div>
      );
  })
}

百分比函数可重用:

// utils percentage exported
export const percentage = (count, total) => ((count * 100) / total).toFixed(2) + '%'

推荐阅读