页面加载时REST API响应闪烁



我有一个组件,它显示用户选择的经销商的联系信息。更具体地说,用户选择他们的位置,设置cookie,然后用于定义API调用。我使用Axios提取该位置经销商的联系信息,将其存储在上下文中,然后根据需要通过几个组件显示信息:标题、;当前位置";组件等。然而,每次刷新页面时,我都会遇到内容闪烁的问题。

我曾尝试将JSON响应存储在本地存储中,但在页面加载的短暂时间内,它显示为未定义,使闪烁继续。显然,我需要消除这一点,以便数据能够持久存在。

我通过ApiContext让它工作,并且我在Header组件中显示数据。以下是两者的代码:

ApiContext.tsx

import React, { createContext, useEffect, useState } from 'react';
import axios from 'axios';
const contextObject = {} as any;
export const context = createContext(contextObject);
export const ApiContext = ({ children }: any) => {
const [selectedDealer, setselectedDealer] = useState(`1`);
useEffect(() => {
axios
.get(`${process.env.GATSBY_API_ENDPOINT}/${selectedDealer}`)
.then((response) => setselectedDealer(response.data));
}, [selectedDealer]);
const changeDealer = (id: any) => {
setselectedDealer(id);
};
const { Provider } = context;
return (
<Provider value={{ data: selectedDealer, changeDealer: changeDealer }}>
{children}
</Provider>
);
};

页眉.tsx

import React, { ReactNode, useContext, useEffect, useState } from 'react';
import Logo from 'assets/svg/logo.svg';
import css from 'classnames';
import { Button } from 'components/button/Button';
import { Link } from 'components/link/Link';
import { MenuIcon } from 'components/menu-icon/MenuIcon';
import { context } from 'contexts/ApiContext';
import { NotificationBar } from '../notification-bar/NotificationBar';
import s from './Header.scss';
import { MainNav } from './navigation/MainNav';
interface HeaderProps {
navigationContent: ReactNode;
}
export const Header = ({ navigationContent }: HeaderProps) => {
const [scrolled, setScrolled] = useState(false);
const [open, setOpen] = useState(false);
const data = useContext(context);

const buttonLabel = data ? data.name : 'Find a Dealer';
const buttonLink = data ? `tel:${data.phone}` : '/find-a-dealer';
useEffect(() => {
const handleScroll = () => {
const isScrolled = window.scrollY > 10;
if (isScrolled !== scrolled) {
setScrolled(!scrolled);
}
};
document.addEventListener('scroll', handleScroll, { passive: true });
return () => {
document.removeEventListener('scroll', handleScroll);
};
}, [scrolled]);
return (
<>
<NotificationBar notificationContent={navigationContent} />
<header className={scrolled ? css(s.header, s.header__scrolled) : s.header}>
<nav className={s.header__navigation}>
<ul className={s.header__container}>
<li className={s.header__logo}>
<Link to="/" className={s.header__link}>
<Logo />
</Link>
</li>
<li className={s.header__primary}>
<MainNav navigationItems={navigationContent} />
</li>
<li className={s.header__utility}>
<Button href={buttonLink}>{buttonLabel}</Button>
</li>
<li className={s.header__icon}>
<MenuIcon onClick={() => setOpen(!open)} />
</li>
</ul>
</nav>
</header>
</>
);
};

我认为这是因为每次刷新页面时都会触发API调用,所以我想知道是否有任何方法可以更有效地持久化数据?

提前感谢!

您的ApiContext.tsx可以将数据保存在localStorage中,方法如下:

import React, { createContext } from 'react';
import axios from 'axios';
import { makeUseAxios } from 'axios-hooks';
import { useCookie } from 'hooks/use-cookie';
const contextObject = {} as any;
export const context = createContext(contextObject);
const useAxios = makeUseAxios({
axios: axios.create({ baseURL: process.env.GATSBY_API_ENDPOINT }),
});
const loadData = (cookie) => {
const stored = localStorage.getItem("data");
const parsed = JSON.parse(stored);
// You can also store a lastSync timestamp along with the data, so that you can refresh them if necessary
if (parsed) return parsed;
const [{data}] = useAxios(`${cookie}`);
if (!isEqual(parsed, data)) {
localStorage.setItem('data', JSON.stringify(data));
}
return data
}
export const ApiContext = ({ children }: any) => {
const [cookie] = useCookie('one-day-location', '1');
const [{ data }] = loadData(cookie);
const { Provider } = context;
return <Provider value={data}>{children}</Provider>;
};

上面的实现只会获取一次数据,所以记得在代码中的某个时刻刷新它们并更新localStorage项,或者使用时间戳来比较并强制执行我代码中注释的api调用。

请记住,即使是这个实现也可能需要几分之一秒的时间才能完成,因此我建议在应用程序获取所需数据时始终使用加载器/微调器/骨架。

我使用了一个持久化状态的钩子,将其存储在localStorage项中,从而解决了这个问题。

使用PersistState.ts

import { useEffect, useState } from 'react';
export const usePersistState = (key: string, defaultValue: string) => {
const [value, setValue] = useState(() => {
if (typeof window !== 'undefined') {
const stickyValue = window.localStorage.getItem(key);
return stickyValue !== null ? JSON.parse(stickyValue) : defaultValue;
}
});
useEffect(() => {
window.localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
};

然后,在ApiContext中,我设置了默认状态,但当该状态更改时,它会更新并保持该状态。下面是我的上下文组件:

ApiContext.tsx

import React, { createContext, useEffect } from 'react';
import { usePersistState } from 'hooks/use-persist-state';
import axios from 'axios';
const contextObject = {} as any;
export const context = createContext(contextObject);
const LOCAL_STORAGE_KEY_SELECTED_DEALER = 'selectedDealerInformation';
export const ApiContext = ({ children }: any) => {
const [selectedDealer, setselectedDealer] = usePersistState(LOCAL_STORAGE_KEY_SELECTED_DEALER, '1');
useEffect(() => {
axios
.get(`${process.env.GATSBY_API_ENDPOINT}/${selectedDealer}`)
.then((response) => setselectedDealer(response.data));
}, [selectedDealer]);
const changeDealer = (id: any) => {
setselectedDealer(id);
};
localStorage.setItem(LOCAL_STORAGE_KEY_SELECTED_DEALER, JSON.stringify(selectedDealer));
const { Provider } = context;
return (
<Provider value={{ data: selectedDealer, changeDealer: changeDealer }}>{children}</Provider>
);
};

最新更新