React(+ Typescript)组件在更新上下文时不会重新呈现
React (+ Typescript) component not rerendering upon updating Context
我有一个 LaunchItem
组件,它使用 React.Context
获取和设置信息 to/from 本地存储。
我想要实现的是,当组件更新上下文(和本地存储)时,我希望它使用新信息重新呈现,以便它随后更新本地按钮的状态。
问题是,虽然上下文和本地存储的内容似乎都已更新,但项目并未重新呈现。 (当我刷新页面时,我可以看到按钮已经改变了状态,但是,这表明它能够很好地从上下文中获取该信息。
我现在将分享一些代码,希望有人能够理解我可能遗漏的内容,非常感谢您的帮助:)
上下文提供程序设置
type FavoritesContextType = {
favorites: Favorites;
updateFavorites: (category: StorageCategory, item: string) => void;
};
export const FavoritesContext = createContext<FavoritesContextType>(
{} as FavoritesContextType
);
const FavoritesProvider: FC = ({ children }) => {
const [favorites, setFavorites] = useState<Favorites>(
getFromLocalStorage(SOME_CONSTANT)
);
const updateFavorites = (category: StorageCategory, item: string) => {
updateLocalStorage(category, item);
setFavorites(favorites);
};
return (
<FavoritesContext.Provider value={{ favorites, updateFavorites }}>
{children}
</FavoritesContext.Provider>
);
};
export const useFavoritesContext = () => useContext(FavoritesContext);
App.tsx
export const App = () => {
return (
<FavoritesProvider>
{/* Some routing wrapper and a few routes each rendering a component */}
<Route path="/launches" element={<Launches />} />
</FavoritesProvider>
)
Launches.tsx
export const LaunchItem = ({ launch }: LaunchItemProps) => {
const { favorites, updateFavorites } = useFavoritesContext();
const [isFavorite, setIsFavorite] = useState(false);
useEffect(() => {
if (favorites) {
setIsFavorite(
favorites.launches.includes(launch.flight_number.toString())
);
}
}, [favorites]);
return (
{/* The rest of the component, irrelevant */}
<FavoriteButton
isFavorite={isFavorite}
updateFavorites={() => {
updateFavorites(
StorageCategory.Launches,
launch.flight_number.toString()
);
}}
/>
)
FavoriteButton.tsx
export const FavoriteButton = ({
isFavorite,
updateFavorites,
}: FavoriteButtonProps) => {
const handleClick = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
e.preventDefault();
updateFavorites();
};
return (
// Using Link vs a Button to be able to preventDefault of parent Link
<Link
onClick={handleClick}
>
{/* The rest of the component, irrelevant */}
似乎在您的 updateFavorites
函数中您正在调用 setFavorites
并传入现有的 favorites
值。尝试将 updateFavorites
函数写成:
const updateFavorites = (category: StorageCategory, item: string) => {
updateLocalStorage(category, item);
setFavorites(getFromLocalStorage(SOME_CONSTANT));
};
还有其他方法可以确定要传递给 setFavorites
的值,但我重复使用了您的 getFromLocalStorage
函数,因为我不确定您是如何确定该状态值的。
通过这种方式,您将确保您在 setFavorites
中设置的值与现有的 favorites
值不同,因此您将触发 re-render.
我有一个 LaunchItem
组件,它使用 React.Context
获取和设置信息 to/from 本地存储。
我想要实现的是,当组件更新上下文(和本地存储)时,我希望它使用新信息重新呈现,以便它随后更新本地按钮的状态。
问题是,虽然上下文和本地存储的内容似乎都已更新,但项目并未重新呈现。 (当我刷新页面时,我可以看到按钮已经改变了状态,但是,这表明它能够很好地从上下文中获取该信息。
我现在将分享一些代码,希望有人能够理解我可能遗漏的内容,非常感谢您的帮助:)
上下文提供程序设置
type FavoritesContextType = {
favorites: Favorites;
updateFavorites: (category: StorageCategory, item: string) => void;
};
export const FavoritesContext = createContext<FavoritesContextType>(
{} as FavoritesContextType
);
const FavoritesProvider: FC = ({ children }) => {
const [favorites, setFavorites] = useState<Favorites>(
getFromLocalStorage(SOME_CONSTANT)
);
const updateFavorites = (category: StorageCategory, item: string) => {
updateLocalStorage(category, item);
setFavorites(favorites);
};
return (
<FavoritesContext.Provider value={{ favorites, updateFavorites }}>
{children}
</FavoritesContext.Provider>
);
};
export const useFavoritesContext = () => useContext(FavoritesContext);
App.tsx
export const App = () => {
return (
<FavoritesProvider>
{/* Some routing wrapper and a few routes each rendering a component */}
<Route path="/launches" element={<Launches />} />
</FavoritesProvider>
)
Launches.tsx
export const LaunchItem = ({ launch }: LaunchItemProps) => {
const { favorites, updateFavorites } = useFavoritesContext();
const [isFavorite, setIsFavorite] = useState(false);
useEffect(() => {
if (favorites) {
setIsFavorite(
favorites.launches.includes(launch.flight_number.toString())
);
}
}, [favorites]);
return (
{/* The rest of the component, irrelevant */}
<FavoriteButton
isFavorite={isFavorite}
updateFavorites={() => {
updateFavorites(
StorageCategory.Launches,
launch.flight_number.toString()
);
}}
/>
)
FavoriteButton.tsx
export const FavoriteButton = ({
isFavorite,
updateFavorites,
}: FavoriteButtonProps) => {
const handleClick = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
e.preventDefault();
updateFavorites();
};
return (
// Using Link vs a Button to be able to preventDefault of parent Link
<Link
onClick={handleClick}
>
{/* The rest of the component, irrelevant */}
似乎在您的 updateFavorites
函数中您正在调用 setFavorites
并传入现有的 favorites
值。尝试将 updateFavorites
函数写成:
const updateFavorites = (category: StorageCategory, item: string) => {
updateLocalStorage(category, item);
setFavorites(getFromLocalStorage(SOME_CONSTANT));
};
还有其他方法可以确定要传递给 setFavorites
的值,但我重复使用了您的 getFromLocalStorage
函数,因为我不确定您是如何确定该状态值的。
通过这种方式,您将确保您在 setFavorites
中设置的值与现有的 favorites
值不同,因此您将触发 re-render.