Gatsbyjs 和 localStorage:持久化状态

时间:2021-02-17 18:23:12

标签: javascript local-storage gatsby react-context context-api

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

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

这是我处理 GDPR_Accepted 状态的 Context 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>

然后,在我的布局组件中,我使用三元组来决定是否应显示 GDPR 横幅。我从 Context API const state = useContext(GlobalStateContext); 访问状态,然后使用三元:

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

所有这些都有效,但我遇到了在用户离开和回来时保持状态的问题。我想到的一些可能的问题:

  • Gatsby 使用服务器端渲染,并且该语言中内置的许多 Javascript 对象(例如 window 甚至 localStorage)在 Gatsby 构建时由于 SSR 会引发错误。我在使用 localStorage 时没有遇到这个问题,这很奇怪。
  • localStorage 应该只存储 strings,但是当我在 localStorage 中存储 strings 时,我的 GDPR 横幅无法工作.如果我使用 boolean,我只能让它工作。出于某种原因,布尔值有效,但字符串无效。
  • 我正在使用 context 并且状态决定是否显示横幅,我应该直接检查 localStorage 吗?如果是这样,怎么办?

1 个答案:

答案 0 :(得分:0)

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