【问题标题】:Gatsbyjs & localStorage: Persisting stateGatsbyjs & localStorage:持久化状态
【发布时间】:2021-05-20 16:30:54
【问题描述】:

我正在为我的网站制作 GDPR 横幅。我希望这个横幅出现在我网站的每个页面上,直到用户单击接受按钮。在我的 Gatsby 站点中,我使用 Context API 来存储用户是否已接受条款,并在本地存储中使用一种称为 GDPR_Accepted 的状态。我将其初始化为 false,当用户单击 GDPR 横幅中的接受按钮时,我将其切换为 true。设置为 true 后,GDPR 横幅不应显示在任何页面上。

我可以使用此功能,除非用户离开我的网站并返回 GDPR_Accepted 重置为 false,并且即使用户之前已接受条款,GDPR 横幅也会再次显示。为什么用户离开时 localStorage 不持久化数据?

这是我处理 GDPR_Accepted 状态的上下文 API 代码:

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 横幅的组件,在此组件中,我使用以下命令切换存储在 localStorage 中的 GDPR_Accepted 状态:

 <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 应该只存储 strings,但是当我将 strings 存储在 localStorage 中时,我的 GDPR 横幅无法正常工作。如果我使用 boolean,我只能让它工作。出于某种原因,booleans 有效,但 strings 无效。
  • 我正在使用 context 并且它是决定是否显示横幅的状态,我应该直接检查localStorage 吗?如果有,怎么做?

【问题讨论】:

    标签: javascript local-storage gatsby react-context


    【解决方案1】:

    看起来您在 GlobalContextProvider 定义中的 useEffect 挂钩正在重置 localStorage 键的值。每次安装组件(即每次页面加载)时,此功能将(至少)运行。无需在每次页面加载时初始化 localStorage 键。您调用setItem 的唯一位置应该是按钮的onClick

    【讨论】:

      猜你喜欢
      • 2018-05-21
      • 2019-05-12
      • 2011-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-07
      • 2021-10-01
      相关资源
      最近更新 更多