#javascript #reactjs #react-native #caching #browser-cache
Вопрос:
Когда я что-то меняю на своей странице, например, устанавливаю переключатели или переключаю вкладки, новые сетевые запросы на извлечение изображений отправляются из браузера. Я заметил это на нескольких веб-сайтах, которые я создал, но другого запроса никогда не должно быть; Я не выполняю a fetch
при изменении этих значений во внешнем интерфейсе. Я не понимаю, почему изображения следует запрашивать снова.
Я прикрепил gif, показывающий, что это происходит в приложении, которое я создаю с помощью React Native, хотя я видел это и в своих проектах React. Вы можете видеть, как изображения мерцают при переключении вкладок и сетевых вызовов в devtools справа, и я также беспокоюсь о влиянии на производительность.
Как я могу предотвратить это?
Для контекста поток данных в моем приложении выглядит следующим образом:
- В
App.tsx
MainStackNavigator
компоненте рендеринга. - В
MainStackNavigator
вызове firebase для извлечения данных (включая изображения). Сохраните эти данныеContext
. - При
Home.tsx
рендерингеTabs
компонента, но также создайте массив, содержащий данные tabs, а именно имя компонента для рендеринга и сам компонент. - На вкладках отображается содержимое на основе выбранной вкладки.
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 }}
/>
);
};
Ответ №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
который было завернуто все приложение. Затем, каждый раз, когда я вообще менял состояние, я сталкивался с этой проблемой, потому что приложение перерисовывалось. Я сделал две вещи, чтобы устранить эту проблему:
- Разделите
Context
на отдельные хранилища, а не просто используйте один глобальный объект состояния. Я создал aContentContext
, который содержал все изображения, чтобы состояние сохранялось отдельно от других изменений состояния, и, следовательно, повторные рендеринги не запускались. - Я использовал
useMemo
и переписал карточки (которые вы можете видеть на изображении), чтобы они менялись только при изменении основного массива данных изображений. Это означает, что, независимо от изменений в других переменных состояния, этому компоненту не нужно будет повторно отображать, пока не изменится массив изображений.
Любое из двух решений должно работать само по себе, но я использовал оба на всякий случай.