Как мне предотвратить новые сетевые запросы, сделанные для уже полученных изображений при смене вкладки, изменении формы и т.д. в React / React Native

#javascript #reactjs #react-native #caching #browser-cache

Вопрос:

Когда я что-то меняю на своей странице, например, устанавливаю переключатели или переключаю вкладки, новые сетевые запросы на извлечение изображений отправляются из браузера. Я заметил это на нескольких веб-сайтах, которые я создал, но другого запроса никогда не должно быть; Я не выполняю a fetch при изменении этих значений во внешнем интерфейсе. Я не понимаю, почему изображения следует запрашивать снова.

Я прикрепил gif, показывающий, что это происходит в приложении, которое я создаю с помощью React Native, хотя я видел это и в своих проектах React. Вы можете видеть, как изображения мерцают при переключении вкладок и сетевых вызовов в devtools справа, и я также беспокоюсь о влиянии на производительность.

Как я могу предотвратить это?

Для контекста поток данных в моем приложении выглядит следующим образом:

  1. В App.tsx MainStackNavigator компоненте рендеринга.
  2. В MainStackNavigator вызове firebase для извлечения данных (включая изображения). Сохраните эти данные Context .
  3. При Home.tsx рендеринге Tabs компонента, но также создайте массив, содержащий данные tabs, а именно имя компонента для рендеринга и сам компонент.
  4. На вкладках отображается содержимое на основе выбранной вкладки.

Home.tsx

 export const Home = (): ReactNode => {
  const scenes = [
    {
      key: "first",
      component: EnglishBreakfastHome,
    },
    {
      key: "second",
      component: SecondRoute,
    },
  ];

  return (
    <View flex={1}>
      <Tabs scenes={scenes} />
    </View>
  );
};
 

Tabs.tsx

 export const Tabs = ({ scenes }: TabsProps): ReactNode => {  
  const renderScenes = useMemo(() =>
    scenes.reduce((map, scene) => {
      map[scene.key] = scene.component;
      return map;
    }, {})
  );

  const renderScene = SceneMap(renderScenes);

  const [index, setIndex] = useState(0);
  const [routes] = useState([
    { key: "first", title: "Breakfast" },
    { key: "second", title: "Herbal" },
  ]);

  const renderTabBar = ({ navigationState, position }: TabViewProps) => {
    const inputRange = navigationState.routes.map((_, i) => i);
    return (
      <Box flexDirection="row">
        {navigationState.routes.map((route, i) => {
          const opacity = position.interpolate({
            inputRange,
            outputRange: inputRange.map((inputIndex) =>
              inputIndex === i ? 1 : 0.5
            ),
          });

          return (
            // Tab boxes and styling
          );
        })}
      </Box>
    );
  };

  return (
    <TabView // using react-native-tab-view
      style={{ flexBasis: 0 }}
      navigationState={{ index, routes }}
      renderScene={renderScene}
      renderTabBar={renderTabBar}
      onIndexChange={setIndex}
      initialLayout={{ width: layout.width }}
    />
  );
};
 

Gif моего приложения и сетевых запросов в devtools

Ответ №1:

Посмотрите на что-то вроде react-native-fast-image. Это даже рекомендуется в документах react-native.

Он обрабатывает обналичивание изображений. Из документов:

 const YourImage = () => (
    <FastImage
        style={{ width: 200, height: 200 }}
        source={{
            uri: 'https://unsplash.it/400/400?image=1',
            headers: { Authorization: 'someAuthToken' },
            priority: FastImage.priority.normal,
        }}
        resizeMode={FastImage.resizeMode.contain}
    />
)
 

Ответ №2:

Проблема здесь заключалась вовсе не в кэшировании изображений, а в управлении состоянием.

Я сделал вызов базы данных для извлечения изображений, а затем сохранил этот массив изображений, в AppContext который было завернуто все приложение. Затем, каждый раз, когда я вообще менял состояние, я сталкивался с этой проблемой, потому что приложение перерисовывалось. Я сделал две вещи, чтобы устранить эту проблему:

  1. Разделите Context на отдельные хранилища, а не просто используйте один глобальный объект состояния. Я создал a ContentContext , который содержал все изображения, чтобы состояние сохранялось отдельно от других изменений состояния, и, следовательно, повторные рендеринги не запускались.
  2. Я использовал useMemo и переписал карточки (которые вы можете видеть на изображении), чтобы они менялись только при изменении основного массива данных изображений. Это означает, что, независимо от изменений в других переменных состояния, этому компоненту не нужно будет повторно отображать, пока не изменится массив изображений.

Любое из двух решений должно работать само по себе, но я использовал оба на всякий случай.