5

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

我用来react-native-svg在应用程序中创建一个相当复杂的图形,它存储在一个组件中,保持不变并在父组件中检索。然后这个父组件在画布上定期旋转和平移,但复杂图形的路径不会改变。因此,由于计算量很大,我只想在应用程序启动时计算该图形的 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. 有没有更优雅/更好的方法来做到这一点(例如,我现在根本没有使用 setter 函数,所以我觉得这不是最佳实践)

编辑:

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

4

3 回答 3

9

当您将值传递给该值时,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>
  )
}

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

您可以通过将特定道具添加到依赖数组来确保path仅在特定道具更改时更新:

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

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

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

在这种情况下,你根本不需要状态。

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

使用useMemo将防止在每次渲染时评估昂贵的计算。

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

于 2020-02-19T02:01:45.020 回答
1

您可以使用钩子useMemo,它将值返回给您的 const,它接收返回值的函数以及一个数组,发送一个空的只计算一次,如果需要重新计算,您可以发送一些依赖项、道具或状态当它们改变时的值。

在您的情况下,您可以执行以下操作:

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

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

它是为那个porpuse创建的。

希望能帮助到你 ;)!

于 2020-02-19T01:55:27.650 回答
1

一个更优雅的选择是使用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只记录一次。

于 2020-10-28T02:32:23.437 回答