Reactjs 跳过效果不适用于动态URL';s

Reactjs 跳过效果不适用于动态URL';s,reactjs,react-hooks,Reactjs,React Hooks,我有一个React.SFC/React stateless/functional组件,不幸的是,由于父组件中的redux传入了一些多余的数据,该组件呈现的频率有点太高。目前对此我无能为力,所以我只接受额外的重新渲染器,并使用useEffect确保只在某个属性发生更改时才获取数据。在本例中,它被称为“URL”,是URL的数组(TypeScript URL类型) 下面是一些示例代码,说明了该问题: import React from "react"; import { useState, useEf

我有一个React.SFC/React stateless/functional组件,不幸的是,由于父组件中的redux传入了一些多余的数据,该组件呈现的频率有点太高。目前对此我无能为力,所以我只接受额外的重新渲染器,并使用useEffect确保只在某个属性发生更改时才获取数据。在本例中,它被称为“URL”,是URL的数组(TypeScript URL类型)

下面是一些示例代码,说明了该问题:

import React from "react";
import { useState, useEffect, useMemo } from "react";
import { render } from "react-dom";

import "./styles.css";

const useCustomHook = urls => {
  const [onlyChangeWhenUrlsChange, setOnlyChangeWhenUrlsChange] = useState(
    null
  );
  useEffect(
    () => {
      setOnlyChangeWhenUrlsChange(Math.random());
    },
    [urls]
  );
  return onlyChangeWhenUrlsChange;
};

const dynamicUrls = (pageRouteParamId, someDynamicUrlParam) => {
  return [
    {
      pageRouteParamId: 1337,
      urls: [new URL(`https://someurl.com/api?id=${someDynamicUrlParam}`)]
    }
  ];
};

const SomePage: React.SFC<any> = ({
  simulateFrequentUpdatingData,
  pageRouteParamId
}) => {
  const someOtherId = 1;
  // As suggested in SO answer, using useMemo seems to work, but will that not create a memory leak?
  // Is there any good alternative?
  // const urls = useMemo(() => dynamicUrls(pageRouteParamId, someOtherId).find(url => url.pageRouteParamId === pageRouteParamId).urls, [pageRouteParamId, someOtherId]);
  const urls = dynamicUrls(pageRouteParamId, 1).find(
    url => url.pageRouteParamId === 1337
  ).urls;
  return (
    <div>
      <p>parent</p>
      <p>{simulateFrequentUpdatingData}</p>
      <p>
        Page route param id (in real app this would come from react-router route
        param): {pageRouteParamId}
      </p>
      {urls && urls.length && <MyStateLessFunctionalComponent {...{ urls }} />}
      <p>
        Page route param id (in real app this would come from react-router route
        param): {pageRouteParamId}
      </p>
      {urls && urls.length && (
        <MyStateLessFunctionalComponentWithHook {...{ urls }} />
      )}
    </div>
  );
};

const MyStateLessFunctionalComponent: React.SFC<any> = ({ urls }) => {
  const [onlyChangeWhenUrlsChange, setOnlyChangeWhenUrlsChange] = useState(
    null
  );
  useEffect(
    () => {
      setOnlyChangeWhenUrlsChange(Math.random());
    },
    [urls]
  );
  return (
    <div>
      <p>MyStateLessFunctionalComponent</p>
      <p>{JSON.stringify(urls)}</p>
      <p>This should only change when urls change {onlyChangeWhenUrlsChange}</p>
    </div>
  );
};

const MyStateLessFunctionalComponentWithHook: React.SFC<any> = ({ urls }) => {
  const onlyChangeWhenUrlsChange = useCustomHook(urls);
  return (
    <div>
      <p>MyStateLessFunctionalComponentWithHook</p>
      <p>{JSON.stringify(urls)}</p>
      <p>This should only change when urls change {onlyChangeWhenUrlsChange}</p>
    </div>
  );
};

function App() {
  const [
    simulateFrequentUpdatingData,
    setSimulateFrequentUpdatingData
  ] = useState(null);
  const [pageRouteParamId, setPageRouteParamId] = useState(1337);
  useEffect(() => {
    setInterval(() => setSimulateFrequentUpdatingData(Math.random()), 1000);
  }, []);

  return (
    <div className="App">
      <SomePage {...{ simulateFrequentUpdatingData, pageRouteParamId }} />
    </div>
  );
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);
从“React”导入React;
从“react”导入{useState、useEffect、useMemo};
从“react dom”导入{render};
导入“/styles.css”;
const useCustomHook=URL=>{
const[onlychangewerlschange,setonlychangewerlschange]=useState(
无效的
);
使用效果(
() => {
setonlychangewerlschange(Math.random());
},
[网址]
);
仅返回更改WherNursChange;
};
常量dynamiccurls=(pageRouteParamId,SomedynamiccurlParam)=>{
返回[
{
pageRouteParamId:1337,
URL:[新URL(`https://someurl.com/api?id=${somedynamicCurlParam}`)]
}
];
};
const SomePage:React.SFC


正如下面的答案中所建议的,useMemo似乎解决了这个问题(参见第36行)

我的猜测是,
URL
是在树的更高的渲染中声明的,因此每次都会获得一个新的标识。您可以在声明位置
usemo
将deps数组中的
url
字符串化,也可以使用
useRef
防止重新运行


编辑:比我聪明的人正在讨论这个问题:

如果
url
是字符串数组,则可以将其作为第二个参数传递给useffect

useEffect(() => {
  loadData();
}, urls);

这样,它将检查字符串值,而不是数组引用

有趣。无论有没有自定义挂钩,它都应该能正常工作。你认为你可以在例如中创建一个钩子吗?是的,无论它是自定义钩子,它的行为都应该是相同的。你的
url
道具是什么样子的?即使道具是静态的,它也会重复播放多次?当我回到电脑时,我会制作一个运行片段。(注意第36行)-不幸的是,我得出了错误的结论,在直接使用useEffect和通过另一个钩子使用useEffect时,这确实也是一个问题。我想我需要编辑标题和问题:/URL是从父组件中的函数生成的(也是无状态的,所以在render中是)。但是如果我直接在子组件MyStateLessFunctionalComponent中使用useEffect,它就会起作用。为什么会有不同?我有点不好意思承认,但你的猜测是正确的。不幸的是,我在写这篇文章时得出了错误的结论。我不确定我是否应该批准你的答案并编辑帖子以适应useMemo的答案,或者干脆取消这个问题。关于useMemo,我认为开始使用它是一个很滑的斜坡,但是在我的例子中,URL是基于特定页面/路径的唯一id的动态的,除了使用memo和潜在的内存泄漏之外,还有其他方法吗?这里的实例:(注意第36行)我认为使用
useMemo
不会有内存泄漏的风险,我很确定它只会在内存中保存最后一个已记忆的值。任何旧值都应该被垃圾回收。然而,这让我很担心:“编写代码,使其在没有useMemo的情况下仍能工作,然后添加代码以优化性能。”然而Dan Abramov在我在回答中链接的问题中使用了它。谢谢。读同一行,也有同样的担忧。:-)它是一个URL数组(Typescript URL类型)。