当我在父级中使用 HOC 时,React 会重新渲染我的记忆组件

Sha*_*oux 1 reactjs react-native react-hooks

我遇到了图像闪烁的问题,因为尽管使用了 React.memo,而且它的 props 或状态都没有改变,但它还是无缘无故地渲染了。

在这里成功地正确使用了 React.memo 来完成这项工作,BUUUT,出于我不明白的原因,如果我在父组件中使用高阶组件,备忘录将不再工作,我得到我的眨眼问题又来了。

这里有一个小吃很能说明问题

这是代码:

import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';

let interval = null

const Icon = ({ name }) => {
  // We emulate a rerender of the Icon by logging 'rerender' in the console
  console.log('rerender')
  return <Text>{name}</Text>
}

const Memo = React.memo(Icon, () => true)

const withHOC = (Comp) => (props) => {
  return <Comp {...props}/>
}

export default function App() {
  const [state, setState] = React.useState(0)
  const name = 'constant'
  // Change the state every second
  React.useEffect(() => {
    interval = setInterval(() => setState(s => s+1), 1000)
    return () => clearInterval(interval)
  }, [])
  // Remove this line and replace NewView by View to see the expected behaviour
  const NewView = withHOC(View)
  return (
    <NewView>
      <Memo name={name} />
    </NewView>
  );
}
Run Code Online (Sandbox Code Playgroud)

我不明白为什么我的 HOC 会破坏记忆,而且我不知道如何防止我的应用程序闪烁并仍然能够使用 HOC...

Ric*_*ler 5

您正在渲染函数中重新创建 HOC。因此,React 无法使该组件的任何子组件在渲染之间保持一致。

如果将 HOC 创建移到渲染之外,那么它就会起作用!

const Text = 'span';
const View = 'div';

let interval = null

const Icon = ({ name }) => {
  // We emulate a rerender of the Icon by logging 'rerender' in the console
  console.log('rerender')
  return <Text>{name}</Text>
}

const Memo = React.memo(Icon, () => true)

const withHOC = (Comp) => (props) => {
  return <Comp {...props}/>
}

// move it out here!
// 
const NewView = withHOC(View)
// 

function App() {
  const [state, setState] = React.useState(0)
  const name = 'constant'
  // Change the state every second
  React.useEffect(() => {
    interval = setInterval(() => setState(s => s+1), 1000)
    return () => clearInterval(interval)
  }, [])
  // Remove this line and replace NewView by View to see the expected behaviour
  
  return (
    <NewView>
      <Memo name={name} />
    </NewView>
  );
}
ReactDOM.render(<App />, document.querySelector('#root'));
Run Code Online (Sandbox Code Playgroud)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
Run Code Online (Sandbox Code Playgroud)


编辑:我在另一个答案中看到了您的评论。

好的,但是我如何在我的组件中使用 HOC?因为我需要向临时提供道具和状态......

如果你确实需要在组件内创建 HOC,你可以用 包装它useMemo,这也可以工作,因为如果依赖项useMemo不改变,React 将在渲染之间保留你的 HOC 引用(注意:如果你的钩子这将不起作用每次渲染的依赖关系都会发生变化)。

function App() {
  // ...
  const NewView = useMemo(() => withHOC(View), []);
}
Run Code Online (Sandbox Code Playgroud)

虽然这可行,但可能有点不稳定。一般来说,钩子和 HOC 不是一起使用的模式。React 核心团队创建了 hooks 来取代 HOC。在你继续沿着这条路走之前,我会尝试看看你是否可以将你的 HOC 写成一个钩子。我想你会发现它更加自然。