【问题标题】:React re-renders entire function when state changesReact 在状态改变时重新渲染整个函数
【发布时间】:2020-11-30 23:26:39
【问题描述】:

我正在考虑实现一个加载屏幕来检查是否加载了所有组件,但遇到了这种奇怪的模式。使用下面的代码,我在控制台中得到 App false 来启动,在 delayHTML 函数返回数据的 2000 毫秒后,我得到 LoadComponent mount eventApp true

但随后它又回到了 suspense fallback,我又得到了 2000 毫秒,LoadComponent mount eventApp true 消息再次出现,看起来像是第二次渲染。我怎样才能避免这种情况?

function App() {
  const [fullLoadState, setfullLoadState] = useState(false);
  
  console.log("App " + fullLoadState)

  eventBus.on("FullyLoaded", (data) => setfullLoadState(true));

  return (
    <div>
      <Suspense fallback='Fallback'>
        <LoadComponent resource={delayHTML(2000)}/>
      </Suspense>
      <p>{fullLoadState ? null : "Site not fully loaded" }</p>
    </div>
  );
}

function LoadComponent({resource}){
  useEffect(()=> {
    console.log ('LoadComponent mount event')
    eventBus.dispatch("FullyLoaded", {messsage: 'some message'});
  })
  const html = resource.read();
  return html;
}

export default App;

EventBus 只是 EventListener。 delayHTML 会挂起,直到达到 2000 毫秒才返回一个文本值。

【问题讨论】:

  • 两条消息都是预期的行为。更改状态会导致组件(App)重新渲染。 useEffect w/o 依赖也运行在每个渲染上。
  • 另外你不应该在渲染中执行副作用(比如订阅)。使用适当的清理功能将此代码移动到useEffecteventBus.on("FullyLoaded", (data) =&gt; setfullLoadState(true));

标签: reactjs react-suspense


【解决方案1】:

您可以尝试将您的 useEffect 更改为:

  useEffect(()=> {
    console.log ('LoadComponent mount event')
    eventBus.dispatch("FullyLoaded", {messsage: 'some message'});
  }, [])

【讨论】:

  • 试过了,好像没什么区别
  • 所以你可以试试别的。将您的 eventBus.on 函数更改为此 --> eventBus.on("FullyLoaded", (data) => if(!fullLoadState) setfullLoadState(true));
【解决方案2】:

根据 react 渲染其组件的方式,您可以创建一个变量,分配 delayHTML 并使用它。

例如,

const delayFunc = delayHTML(2000);
...
<LoadComponent resource={delayFunc}/>

这应该可行。

【讨论】:

  • 尝试了一个变体 - const delayFunc = useState(delayHTML(2000))。这有点奏效 - 悬念后备不再有第二次加载,但LoadComponent mount event 在控制台中记录了两次。控制台也有警告:Cannot update a component (App) while rendering a different component (LoadComponent)
  • 可以分享delayHtml函数体吗?
  • 我认为 Yury 可能是对的——状态变化会导致 React 再次触发 render() 函数。函数 delayHTML(ms) { return (wrapPromise(new Promise(resolve => { setTimeout(() => { resolve('abc') }, ms) }))) }
  • 是的,状态变化会导致 React 再次触发渲染方法。这就是 React 的设计方式。
  • 谢谢!已投票,但此处未显示。关于警告信息的任何想法?它不会影响任何事情,但可能不是 React 做事的方式。
猜你喜欢
  • 2020-04-22
  • 2020-01-20
  • 2018-12-31
  • 2018-01-03
  • 2018-11-29
  • 1970-01-01
  • 2021-06-25
  • 2020-09-10
  • 2019-05-22
相关资源
最近更新 更多