我需要能够在我的Gatsby项目中设置和访问Cookie,并且能够使用this tutorial进行可靠的设置。我正在建立一个设置cookie的钩子,并在整个站点中使用它。说完了,这就是助手的样子。
use-cookie.ts
import { useState, useEffect } from 'react';
const getItem = (key) =>
document.cookie.split('; ').reduce((total, currentCookie) => {
const item = currentCookie.split('=');
const storedKey = item[0];
const storedValue = item[1];
return key === storedKey ? decodeURIComponent(storedValue) : total;
}, '');
const setItem = (key, value, numberOfDays) => {
const now = new Date();
// set the time to be now + numberOfDays
now.setTime(now.getTime() + numberOfDays * 60 * 60 * 24 * 1000);
document.cookie = `${key}=${value}; expires=${now.toUTCString()}; path=/`;
};
/**
*
* @param {String} key The key to store our data to
* @param {String} defaultValue The default value to return in case the cookie doesn't exist
*/
export const useCookie = (key, defaultValue) => {
const getCookie = () => getItem(key) || defaultValue;
const [cookie, setCookie] = useState(getCookie());
const updateCookie = (value, numberOfDays) => {
setCookie(value);
setItem(key, value, numberOfDays);
};
return [cookie, updateCookie];
};
我正在像这样调用一个组件的钩子:
DealerList.tsx
import React, { ReactNode, useEffect } from 'react';
import { Container } from 'containers/container/Container';
import { Section } from 'containers/section/Section';
import { Link } from 'components/link/Link';
import s from './DealerList.scss';
import { useCookie } from 'hooks/use-cookie';
interface DealerListProps {
fetchedData: ReactNode;
}
let cookie;
useEffect(() => {
cookie = useCookie();
}, []);
export const DealerList = ({ fetchedData }: DealerListProps) => {
const dealerInfo = fetchedData;
if (!dealerInfo) return null;
const [cookie, updateCookie] = useCookie('one-day-location', 'sacramento-ca');
return (
<>
<Section>
<Container>
<div className={s.list}>
{dealerInfo.map((dealer: any) => (
<div className={s.dealer} key={dealer.id}>
<div className={s.dealer__info}>
<h3 className={s.name}>
{dealer.company.name}
</h3>
<span className={s.address}>{dealer.address.street}</span>
<span className={s.city}>{dealer.address.city} {dealer.address.zip}</span>
</div>
<div className={s.dealer__contact}>
<span className={s.email}>{dealer.email}</span>
<span className={s.phone}>{dealer.phone}</span>
</div>
<div className={s.dealer__select}>
<Link
to="/"
className={s.button}
onClick={() => {
updateCookie(dealer.phone, 10);
}}
>
Select Location
</Link>
</div>
</div>
))}
</div>
</Container>
</Section>
</>
);
};
它在gatsby develop
上运行良好,我可以访问Cookie的值并更改相应显示的联系信息。但是,当我尝试构建或推送到Netlify时,出现此错误。
WebpackError: ReferenceError: document is not defined
我知道这与第4行和第17行的document.cookie
有关,但是我正在努力寻找解决方法。有什么建议?我导入了useEffect
,并且从我的研究中得知与此有关,但是该如何使其正常工作?
谢谢。
答案 0 :(得分:2)
根据Gatsby's Debugging HTML Builds documentation:
您的某些代码引用了“浏览器全局变量”,例如
window
或document
。如果这是您的问题,则应该在上面看到类似的错误 “window
未定义”。要解决此问题,请找到有问题的代码,然后 要么a)在调用代码之前检查是否定义了window
,以便 盖茨比(Gatsby)正在构建时代码未运行(请参见下面的代码示例),或者 b)如果代码在React.js组件的render函数中,请移动 该代码进入componentDidMount生命周期或useEffect
挂钩, 这样可以确保除非在浏览器中,否则代码不会运行。
因此,在不违反钩子规则的情况下,在另一个钩子中调用一个钩子会导致嵌套无限循环。在调用之前,需要确保document
的创建。只需添加一个检查条件:
import { useState } from 'react';
const getItem = (key) => {
if (typeof document !== undefined) {
document.cookie.split(`; `).reduce((total, currentCookie) => {
const item = currentCookie.split(`=`);
const storedKey = item[0];
const storedValue = item[1];
return key === storedKey ? decodeURIComponent(storedValue) : total;
}, ``);
}
};
const setItem = (key, value, numberOfDays) => {
const now = new Date();
// set the time to be now + numberOfDays
now.setTime(now.getTime() + numberOfDays * 60 * 60 * 24 * 1000);
if (typeof document !== undefined) {
document.cookie = `${key}=${value}; expires=${now.toUTCString()}; path=/`;
}
};
/**
*
* @param {String} key The key to store our data to
* @param {String} defaultValue The default value to return in case the cookie doesn't exist
*/
export const useCookie = (key, defaultValue) => {
const getCookie = () => getItem(key) || defaultValue;
const [cookie, setCookie] = useState(getCookie());
const updateCookie = (value, numberOfDays) => {
setCookie(value);
setItem(key, value, numberOfDays);
};
return [cookie, updateCookie];
};
由于您可能正在useCookie
还不存在的组件或页面中调用document
自定义钩子,因此我将使用相同的条件或使用{{1} }具有空的依赖项(useEffect
,现在不会破坏钩子规则):
[]
答案 1 :(得分:2)
我做了一些进一步的研究,发现this simple hook,用此替换了use-cookie.ts
中的代码,对其进行了一些修改(包括在下面),安装了universal-cookie
并且它似乎工作正常。这是新代码:
use-cookie.ts
import { useState } from 'react';
import Cookies from 'universal-cookie';
export const useCookie = (key: string, value: string, options: any) => {
const cookies = new Cookies();
const [cookie, setCookie] = useState(() => {
if (cookies.get(key)) {
return cookies.get(key);
}
cookies.set(key, value, options);
});
const updateCookie = (value: string, options: any) => {
setCookie(value);
removeItem(value);
cookies.set(key, value, options);
};
const removeItem = (key: any) => {
cookies.remove(key);
};
return [cookie, updateCookie, removeItem];
};
但是,如果有人有更好的方法可以做到这一点,请告诉我!