Gatsbyjs & localStorage:持久化状态

Posted

技术标签:

【中文标题】Gatsbyjs & localStorage:持久化状态【英文标题】:Gatsbyjs & localStorage: Persisting state 【发布时间】: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 构建时由于 s-s-r 会引发错误。我使用localStorage 时没有这个问题,这很奇怪。 localStorage 应该只存储 strings,但是当我将 strings 存储在 localStorage 中时,我的 GDPR 横幅无法正常工作。如果我使用 boolean,我只能让它工作。出于某种原因,booleans 有效,但 strings 无效。 我正在使用 context 并且它是决定是否显示横幅的状态,我应该直接检查localStorage 吗?如果有,怎么做?

【问题讨论】:

【参考方案1】:

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

【讨论】:

以上是关于Gatsbyjs & localStorage:持久化状态的主要内容,如果未能解决你的问题,请参考以下文章

如何在 gatsbyjs 中使用参数创建路由

如何在导航上显示提示(GatsbyJS/ReachRouter)

如何使用 GatsbyJS 根据路由渲染组件?

如何在 GatsbyJS 项目中显示图像?

如何在 GatsbyJS 项目中显示图像?

GatsbyJS 中的 GraphQL 过滤器