Я создаю баннер 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
напрямую? Если да, то как?