useState 在执行作为 props 传递的函数时导致速度变慢

useState causing slowness when executing function passed as props

我有一个 React 本机应用程序,其中有一个颜色配置、一种主题、一个特定的屏幕,我传递了一个像 props 这样的函数,它被执行并更新全局颜色,但是它会导致延迟大约一秒

这是我的应用程序

import { AppLoading } from 'expo';
import { Asset } from 'expo-asset';
import * as Font from 'expo-font';
import React, { useState, useEffect } from 'react';
import { Platform, StatusBar, StyleSheet, View, AsyncStorage } from 'react-native';
import { Ionicons } from '@expo/vector-icons';

import AppNavigator from './src/navigation/AppNavigator';

export default function App(props) {
  const [isLoadingComplete, setLoadingComplete] = useState(false);
  const [colors, setColor] = useState({});
  // useEffect(() => {
  //   getColor();
  // }, []);

  const setDefaultColor = skin => {
    const data = {
      name: skin?.name,
      primary: skin?.color?.primary,
      secondary: skin?.color?.secondary,
      complementary: skin?.color?.complementary,
    };
    setColor(data);
  };

  // async function getColor(skin) {
  //   const getColors = await AsyncStorage.getItem('colors');
  //   if (getColors) {
  //     const { color, name } = JSON.parse(getColors);
  //   } else {
  //     setColor({
  //       name: 'Preto',
  //       primary: '#000000',
  //       secondary: '#fff',
  //       complementary: '#000000',
  //     });
  //   }
  // }

  if (!isLoadingComplete && !props.skipLoadingScreen) {
    return (
      <AppLoading
        startAsync={loadResourcesAsync}
        onError={handleLoadingError}
        onFinish={() => handleFinishLoading(setLoadingComplete)}
      />
    );
  }
  return (
    <View style={styles.container}>
      {Platform.OS === 'ios' && <StatusBar barStyle="default" />}
      <AppNavigator screenProps={{ colors, handleColor: setDefaultColor }} {...props} />
    </View>
  );
}

async function loadResourcesAsync() {
  await Promise.all([
    Asset.loadAsync([
      require('./src/assets/images/robot-dev.png'),
      require('./src/assets/images/robot-prod.png'),
    ]),
    Font.loadAsync({
      // This is the font that we are using for our tab bar
      ...Ionicons.font,
      // We include SpaceMono because we use it in HomeScreen.js. Feel free to
      // remove this if you are not using it in your app
      Corbelb: require('./src/assets/fonts/corbelb.ttf'),
      Corbel: require('./src/assets/fonts/corbel.ttf'),
    }),
  ]);
}

function handleLoadingError(error) {
  // In this case, you might want to report the error to your error reporting
  // service, for example Sentry
  console.warn(error);
}

function handleFinishLoading(setLoadingComplete) {
  setLoadingComplete(true);
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
});

这是我进行颜色配置的屏幕

import React from 'react';

import { View, Modal, AsyncStorage, StyleSheet, Text, TouchableOpacity } from 'react-native';
import Mdi from 'react-native-vector-icons/MaterialCommunityIcons';

export default function SettingsColors(props) {
  const { modalVisible, closeModal, screenProps } = props;

  const data = [
    {
      name: 'Azul',
      color: {
        primary: '#0061ab',
        secondary: 'white',
        complementary: '#01256f',
      },
    },
    {
      name: 'Vermelho',
      color: {
        primary: '#ab000d',
        secondary: 'white',
        complementary: '#7e000a',
      },
    },
    {
      name: 'Laranja',
      color: {
        primary: '#ff7200',
        secondary: 'white',
        complementary: '#ac4d00',
      },
    },
    {
      name: 'Preto',
      color: {
        primary: '#000000',
        secondary: '#fff',
        complementary: '#000000',
      },
    },
    {
      name: 'Roxo',
      color: {
        primary: '#670097',
        secondary: 'white',
        complementary: '#480069',
      },
    },
    {
      name: 'Verde',
      color: {
        primary: '#1f8f04',
        secondary: 'white',
        complementary: '#177700',
      },
    },
    {
      name: 'Rosa',
      color: {
        primary: '#e402b1',
        secondary: 'white',
        complementary: '#9b0078',
      },
    },
    {
      name: 'Branco',
      color: {
        primary: '#ffffff',
        secondary: 'black',
        complementary: 'white',
      },
    },
  ];

  function handleChangeColor(skin) {
    screenProps.handleColor(skin);
  }

  return (
    <Modal
      animationType="fade"
      transparent
      visible={modalVisible}
      onRequestClose={() => closeModal()}
    >
      <View style={styles.container}>
        <View style={styles.header}>
          <Mdi style={{ padding: 5 }} name="palette" color="black" size={30} />
          <Text style={{ fontSize: 20 }}>Skins</Text>
        </View>

        <View style={styles.containerButton}>
          {data.map((item, index) => (
            <TouchableOpacity
              key={index}
              style={[styles.button, { backgroundColor: item.color.primary }]}
              onPress={() => handleChangeColor(item)}
            >
              <Text
                style={[
                  styles.text,
                  {
                    color: `${item.color.primary === '#ffffff' ? 'black' : 'white'}`,
                  },
                ]}
              >
                {item.name}
              </Text>
            </TouchableOpacity>
          ))}
        </View>
      </View>
    </Modal>
  );
}

const styles = StyleSheet.create({
  container: {
    marginTop: 80,
    elevation: 10,
    padding: 20,
    borderRadius: 20,
    margin: 20,
    backgroundColor: '#fff',
  },
  header: {
    width: '100%',
    flexDirection: 'row',
    alignItems: 'center',
    alignSelf: 'flex-start',
    borderBottomWidth: 1,
    marginBottom: 10,
  },
  containerButton: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    alignItems: 'center',
    justifyContent: 'center',
  },
  button: {
    alignItems: 'center',
    justifyContent: 'center',
    height: 60,
    minWidth: 80,
    padding: 10,
    marginVertical: 10,
    margin: 5,
    borderRadius: 10,
    elevation: 5,
  },
  text: {
    color: 'white',
    fontWeight: 'bold',
  },
});

任何帮助或对发生的事情的解释,我将不胜感激。

看起来每当您更新颜色时,都会从项目的根部开始重新渲染,这很可能是导致速度变慢的原因。

我建议对此类行为使用 React Contexts。您的主要上下文将公开活动颜色和设置颜色的方法,可以通过消费者访问这些颜色。 (文档页面上的一个示例实际上是将它用于主题化组件,因此希望这会有所帮助。)