#reactjs #local-storage #global-state
Вопрос:
Я работаю над проектом, в котором я реализовал глобальное состояние, используя то, что доступно в ReactJS, сторонняя библиотека не используется.
Когда я устанавливаю глобальное состояние, я затем также добавляю его в локальное хранилище, поэтому, если браузер перезагрузится, идея состоит в том, что я смогу извлечь данные из локального хранилища и перевести их в глобальное состояние, но, похоже, это не работает, поскольку я продолжаю получать неопределенное ошибка при попытке получить доступ к свойству в глобальном состоянии после перезагрузки страницы.
Мой GlobalStateProvider выглядит следующим образом:
import React, {createContext, useState, useContext, Dispatch, SetStateAction, useEffect} from "react";
export interface GlobalStateInterface {
trial: {
in_trial: boolean,
days_of_trial_remaining: number
}
payment_failed: {
last_payment_failed: boolean,
payment_time_required: number,
last_payment_failed_reason: string,
payment_required: boolean
}
}
const GlobalStateContext = createContext({
globalState: {} as Partial<GlobalStateInterface>,
setGlobalState: {} as Dispatch<SetStateAction<Partial<GlobalStateInterface>>>,
});
const GlobalStateProvider = ({
children,
value = {} as GlobalStateInterface,
}: {
children: React.ReactNode;
value?: Partial<GlobalStateInterface>;
}) => {
const [globalState, setGlobalState] = useState(value);
return (
<GlobalStateContext.Provider value={{ globalState, setGlobalState }}>
{children}
</GlobalStateContext.Provider>
);
};
const useGlobalState = () => {
const context = useContext(GlobalStateContext);
if (!context) {
throw new Error("useGlobalState must be used within a GlobalStateContext");
}
return context;
};
export { GlobalStateProvider, useGlobalState };
Я создал базовый компонент, который, как я ожидал, я мог бы использовать, чтобы проверить, содержит ли localStorage поставщика глобального состояния, и если да, то загрузить его в глобальное состояние, поэтому этот компонент содержит следующее:
import * as React from "react";
import {useEffect} from "react";
import {useGlobalState} from "./GlobalStateProvider";
export default function BaseComponent(props) {
const { setGlobalState } = useGlobalState();
useEffect(() => {
let tempGlobalStorage = localStorage.getItem("global_state");
console.log("Temp Global State: ", tempGlobalStorage);
if (tempGlobalStorage !== null) {
const tempGlobalStorageJson = JSON.parse(tempGlobalStorage);
setGlobalState({...tempGlobalStorageJson});
}
}, []);
return (
<>
{props.children}
</>
)
}
My App.js looks like the following: (I’m only showing what is being returned in App.js as I don’t think anything is relevant)
return (
<Elements stripe={stripePromise}>
<GlobalStateProvider>
<BaseComponent>
<BrowserRouter>
<div className='h-full'>
<Switch>
<Route path="/" render={(props) => <Login {...props} /> } exact />
<Route path="/login/:msg?/:redirect?" render={(props) => <Login {...props} /> } exact />
<Route path="/choose-plan" render={() => <ChoosePlan /> } exact />
<Route path="/signup/:plan" render={(props) => <SignUp {...props} /> } exact />
<Route path="/dashboard" render={() => <Dashboard /> } exact />
<Route path="/project-settings/:project_id" render={(props) => <ProjectSettings {...props} /> } />
<Route path="/settings" render={() => <Settings /> } exact />
<Route path='/add-project' render={() => <AddProject /> } exact />
<Route path='/final-project-setup/:platform/:project_id/:api_key' render={(props) => <FinalProjectSetup {...props} /> } />
<Route path='/crash-details/:project_id/:project_type/:crash_group_id?/:comment_id?' render={(props) => <CrashDetails {...props} /> } />
<Route path='/team-members' render={() => <ManageTeamMembers /> } />
<Route path='/add-team-member' render={() => <AddTeamMember /> } />
<Route path='/register-new-user/:invite_params?' render={(props) => <RegisterNewUser {...props} /> } />
<Route path='/account-billing' render={() => <AccountAndBilling /> } exact />
<Route path='/forgotten-password' render={() => <ForgottenPassword /> } exact />
<Route path='/reset-password/:resetPasswordData' render={(props) => <ResetPassword {...props} /> } />
<Route path='/status' render={() => <Status /> } />
<Route render={() => <NotFound />}/>
</Switch>
</div>
</BrowserRouter>
</BaseComponent>
</GlobalStateProvider>
</Elements>
);
Как вы можете видеть в базовом компоненте, я выхожу из того, что находится в localStorage, оно ничего не выводит при перезагрузке страницы, как будто я получаю доступ к глобальному состоянию в одном из компонентов маршрута, срабатывает до того, как базовый компонент запускает useEffect.
Ниже приведен пример, в котором задается состояние и глобальное хранилище:
const tempGlobalState = globalState;
tempGlobalState.trial = {
in_trial: response.data.in_trial,
days_of_trial_remaining: response.data.in_trial ? response.data.trial_days_remaining : null
}
tempGlobalState.payment_failed = {
last_payment_failed: response.data.last_payment_failed,
last_payment_failed_reason: response.data.last_payment_failed_reason,
payment_time_required: response.data.payment_time_required,
payment_required: false //Still within the 7 day grace period for non payment
}
/*tempGlobalState.trial.in_trial = response.data.in_trial;
if (response.data.in_trial)
{
tempGlobalState.trial.days_of_trial_remaining = response.data.trial_days_remaining;
}*/
localStorage.setItem("global_state", JSON.stringify(tempGlobalState));
setGlobalState({...tempGlobalState});
Комментарии:
1. Где вы устанавливаете значение
global_state
? Если вы никогда не устанавливали его в localStorage, то вы не можете ожидать, что он вернет что-либо при перезагрузке.2. Я, очевидно, проверил, что локальное хранилище имеет значение, установленное в инструментах разработчика Chrome. Но я добавил к вопросу пример его хранения в локальном хранилище.
3. Хм … может быть, ваше локальное хранилище находится в плохом состоянии. Я смог заставить ваш код работать с упрощенной версией GlobalState: codesandbox.io/s/stoic-pine-rnrb8 Ваша основная идея здрава. Это может помочь максимально упростить устранение неполадок…
4. Странно, codesandbox каким-то образом был поврежден. Если это будет полезно, я могу попытаться восстановить его. LMK.
5. Мне удалось заставить его работать. Похоже, что useEffect не срабатывал, я реализовал его до возврата компонента и проверил, что состояние еще не установлено, а если нет, то извлеките его из localstorage и установите глобальное хранилище. Но все же спасибо за вашу помощь