如何确保组件内的常量仅在 React (Native) 中使用 hooks 启动时计算一次?

How to ensure a constant inside a component is only calculated once on start in React (Native) with hooks?

我目前正在创建一个 React Native 应用程序,但仍然不确定如何最好地处理我的用例的状态。

我使用 react-native-svg 在应用程序中创建了一个相当复杂的图形,它存储在组件中,保持不变并在父组件中检索。然后这个父组件在canvas上有规律的旋转和平移,但是复图的路径没有变化。因此,由于计算量很大,我只想在应用程序启动时计算该图形的 SVG 路径,而不是在旋转或平移父组件时计算。目前,我的代码结构如下所示:

图形组件

const Figure = (props) => {
    const [path, setPath] = useState({FUNCTION TO CALCULATE THE SVG PATH});

    return(
        <G>
            <Path d={path} />
        </G>
    )
}

父组件

const Parent = (props) => {
    return (
        <View>
            <Svg>
                <G transform={ROTATE AND TRANSFORM BASED ON INTERACTION}>
                    <Figure />
                </G>
            </Svg>
        </View>
    )
}

如您所见,我正在为路径数据使用状态。我现在的问题:

  1. 我在这里确保这条路径只在开始时计算一次吗?
  2. 是否有更多 elegant/better 的方法(例如,我现在根本没有使用 setter 函数,所以我觉得这不是最佳做法)

编辑:

计算路径的函数取决于我从父组件传递的一些道具。

你可以使用钩子useMemo,它returns你的const的值,它接收returns这个值的函数,也是一个数组,发送一个空的只计算一次,如果需要,你可以发送一些依赖项,道具或状态,以便在它们发生变化时重新计算值。

在你的情况下,你可以这样做:

const Figure = (props) => {
    const path = React.useMemo(() => {
      // calculate and return value for path
    }, []);

    return(
        <G>
            <Path d={path} />
        </G>
    )
}

它是为那只海豚创建的。

希望对您有所帮助 ;)!

当您将值传递给 useState 时,该值用于初始化状态。它不会在每次组件重新呈现时都设置,因此在您的情况下,path 仅在组件安装时设置。

即使道具变了,path状态也不会变

由于您的初始状态取决于道具,您需要做的就是从道具中提取相关道具并将其传递给计算初始 path 值的函数:

const Figure = (props) => {
  // get relevant prop
  const { importantProp } = props;

  // path will never change, even when props change
  const [path] = useState(calculatePath(importantProp));

  return(
    <G>
      <Path d={path} />
    </G>
  )
}

但是,即使 path 值未重新初始化,calculatePath 函数仍会在每次渲染时进行评估。如果 calculatePath 是一个昂贵的操作,那么考虑使用 useMemo 代替:

您可以确保 path 仅在特定道具更改时更新,方法是将该道具添加到依赖项数组:

const Figure = (props) => {
  const { importantProp } = props;

  const path = useMemo(() => calculatePath(importantProp), [importantProp]);

  return(
    <G>
      <Path d={path} />
    </G>
  )
}

在那种情况下,您根本不需要状态。

importantProp 添加到 useMemo 依赖项数组意味着每次 importantProp 更改时,React 都会重新计算您的 path 变量。

使用 useMemo 将避免在每次渲染时进行昂贵的计算。

我创建了一个 CodeSandbox example,您可以在控制台中看到路径仅在指定的 prop important 更改时才重新计算。如果您更改任何其他道具,则 path 不会重新计算。

一个更优雅的选择是使用 useState 的回调形式。如果你给它传递一个函数,这个函数只会在需要计算初始状态时被调用——也就是说,在初始渲染时:

const [path, setPath] = React.useState(heavyCalculation);

const heavyCalculation = () => {
  console.log('doing heavy calculation');
  return 0;
};

const App = () => {
  const [path, setPath] = React.useState(heavyCalculation);
  React.useEffect(() => {
    setInterval(() => {
      setPath(path => path + 1);
    }, 1000);
  }, []);
  return 'Path is: ' + path;
};
ReactDOM.render(<App />, document.querySelector('.react'));
<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 class="react"></div>

如您在上面的代码片段中所见,doing heavy calculation 仅记录一次。