Gatsbyjs и localStorage: постоянное состояние

Я создаю баннер GDPR для своего сайта. Я хочу, чтобы этот баннер появлялся на каждой странице моего сайта, пока пользователь не нажмет кнопку принятия. На своем сайте Gatsby я использую Context API, чтобы узнать, принял ли пользователь условия, с помощью элемента состояния в локальном хранилище, называемого GDPR_Accepted. Я инициализирую его как false, и когда пользователь нажимает кнопку принятия в баннере GDPR, я переключал его на true. После установки значения true баннер GDPR не должен отображаться ни на одной странице.

У меня эта функция работает, за исключением случаев, когда пользователь покидает мой сайт и возвращается, GDPR_Accepted сбрасывает значение false, и баннер GDPR отображается снова, даже если пользователь ранее принял условия. Почему localStorage не сохраняет данные, когда пользователь уходит?

Вот мой код Context API, в котором я обрабатываю состояние GDPR_Accepted:

function reducer(state, action) {
    switch(action.type) {
        case TOGGLE_GDPR: {
            return {
                ...state,
                GDPR: state.GDPR === false ? true : false
            }
        }
        default: {
            return {
                ...state
            }
        }
    }
}

export const GlobalContextProvider = ({ children }) => {
    const [state, dispatch] = React.useReducer(reducer, initialState)

    useEffect(() => {
        if (storageAvailable('localStorage')) {
            localStorage.setItem('GDPR_Accepted', state.GDPR)
          }
          else {
            return 0;
          }
    }, [state])

    return (
        <GlobalStateContext.Provider value={state}>
            <GlobalDispatchContext.Provider value={dispatch}>
                {children}
            </GlobalDispatchContext.Provider>
        </GlobalStateContext.Provider>
    )
}

У меня также есть эта функция, которую я взял из документации MDN, которая сначала проверяет, доступно ли локальное хранилище:

// Checks if localStorage is available in the user's browser
   function storageAvailable(type) {
    var storage;
    try {
        storage = window[type];
        var x = '__storage_test__';
        storage.setItem(x, x);
        storage.removeItem(x);
        return true;
    }
    catch(e) {
        return e instanceof DOMException && (
            // everything except Firefox
            e.code === 22 ||
            // Firefox
            e.code === 1014 ||
            // test name field too, because code might not be present
            // everything except Firefox
            e.name === 'QuotaExceededError' ||
            // Firefox
            e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
            // acknowledge QuotaExceededError only if there's something already stored
            (storage && storage.length !== 0);
        }
    }

В моем интерфейсе у меня есть компонент, который отображает фактический баннер GDPR, внутри этого компонента я переключаю состояние GDPR_Accepted, хранящееся в localStorage, с помощью этого:

 <Button className={styles.acceptButton} onClick={async () => {
        dispatch({ type: "TOGGLE_GDPR" })
 }}>Accept All Cookies</Button>

Затем в моем компоненте Layout я использую троицу, чтобы решить, следует ли отображать баннер GDPR или нет. Я получаю доступ к состоянию из Context API, const state = useContext(GlobalStateContext);, а затем использую троичный:

{
   state.GDPR === false ?                    
    <GDPR />
   : null
}

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

  • Gatsby использует рендеринг на стороне сервера, и многие объекты Javascript, встроенные в язык (например, window или даже localStorage), выдают ошибку при сборке Gatsby из-за SSR. У меня не возникает этой проблемы, когда я использую localStorage, что странно.
  • localStorage должен хранить только строки, но я не могу заставить мой баннер GDPR работать, когда я храню строки в localStorage. Я могу заставить это работать, только если использую логическое. По какой-то причине логические работают, а строки - нет.
  • Я использую контекст, и он определяет, отображается ли баннер. Должен ли я проверять localStorage напрямую? Если да, то как?

person Nick Kinlen    schedule 17.02.2021    source источник


Ответы (1)


Похоже, ваш хук useEffect в определении GlobalContextProvider сбрасывает значение ключа localStorage. Эта функция будет запускаться (как минимум) каждый раз, когда компонент монтируется (то есть при каждой загрузке страницы). Нет необходимости инициализировать ключ localStorage при каждой загрузке страницы. Единственное место, куда вы звоните setItem, должно быть в onClick вашей кнопки.

person jamison    schedule 26.02.2021