
NextJS利用Cookie实现自动夜间模式主题
本文字数 0 | 阅读时长 ≈ 0 分钟
category
技术工具
tags
开发
NextJS
ReactJS
type
Post
slug
nextjs-cookie-localStorage-darkMode
summary
NextJS服务端渲染时,获取客户端的cookie或localStorage的解决方案
status
Published
date
Nov 3, 2021
icon
password
文章来源说明
🤔前言
我在我的Reactjs项目中使用了Nextjs。现在需求是在客户端的cookie中缓存用户选择的主题,用户打开页面时展示该主题的界面。用户关闭浏览器后,下次打开页面主题又回到默认。
而在nextjs中,服务器端通过调用
getInitialProps() 以进行第一页加载。我的其它页面渲染是在服务端getStaticProps()完成的,故而无法获取客户端的 localstorage 、以及cookie,也就不便于做一些基于浏览器缓存的操作。让人头大。可使用的API
1.ReactJS获取cookie
# 安装
yarn add react-cookiesimport cookie from 'react-cookies'
export const loadDataFromCookies = (k) => {
return cookie.load(k)
}
export const saveDatatoCookies = (k,v) => {
cookie.save(k,v, { path: '/' })
}2.ReactJS获取LocalStorage
yarn add localStorageimport localStorage from 'localStorage'
export const loadDataFromLocalStorage = (k) => {
return localStorage.getItem(k)
}
export const saveDatatoLocalStorage = (k,v) => {
localStorage.setItem(k,v)
}一种方案可能的方案
直接在服务端获取客户端请求中的Cookie:我们可以在网站的第一页访问入口处获取,也就是
_document.js中的getInitialProps中获取:import Document, { Head, Html, Main, NextScript } from 'next/document'
import jsHttpCookie from 'cookie'
class MyDocument extends Document {
static async getInitialProps (ctx) {
const initialProps = await Document.getInitialProps(ctx)
// 将客户端cookie存入服务端
if (ctx && ctx.req && ctx.req.headers) {
const cookies = ctx.req.headers.cookie
if (typeof cookies === 'string') {
initialProps.cookies = jsHttpCookie.parse(cookies)
}
}
return { ...initialProps }
}
render () {
return (
<Html>
<Head>
<script id="session" type="application/json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(this.props.cookies, null, 2)
}}
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument然而这里的 initialProps.cookies没有办法直接传给别的组件。一种可行方案是作为URL的传参,放在全局路由中,这样就可以在其他组件中获取到参数。而这样会破坏页面地址的美观性,最后还是采取了如下另一种方案。
📝由前端进行Cookie读取和渲染
利用useEffect()函数,由客户端在页面渲染生效时,进行默认主题的读取和切换:将cookie中保存的主题信息,添加到相应DOM的classList当中,例如:
document.getElementById('wrapper').classList.add('theme') 这里我创建了一个
Provider,用useState进行变量的绑定,便于其他模块调用useTheme勾子来实现全局主题的手动切换。theme.js文件:
import { useContext, createContext, useState, useEffect, useRef } from 'react'
import cookie from 'react-cookies'
const ThemeContext = createContext()
export function ThemeProvider ({ children }) {
const [theme, changeTheme] = useState(loadUserThemeFromCookies())
// 由于Server采用服务端静态渲染,无法获取前端Cookie配置,故在渲染hooks中做初始化主题
useEffect(() => {
const baseLayoutClass = document.getElementById('wrapper').classList
if (!baseLayoutClass.contains(theme)) {
baseLayoutClass.add(theme)
}
})
return (
<ThemeContext.Provider value={{ theme, changeTheme }}>{children}</ThemeContext.Provider>
)
}
export const loadUserThemeFromCookies = () => {
return cookie.load('theme')
}
export const saveTheme = (newTheme) => {
cookie.save('theme', newTheme, { path: '/' })
}
export const useTheme = () => useContext(ThemeContext)DarkModeButton.js
实现点击按钮切换主题
import { loadUserThemeFromCookies, saveTheme, useTheme } from '@/lib/theme'
const DarkModeButton = () => {
const { changeTheme } = useTheme()
const userTheme = loadUserThemeFromCookies()
// 用户手动设置主题
const handleChangeDarkMode = () => {
const newTheme = (userTheme === 'light' ? 'dark' : 'light')
saveTheme(newTheme)
changeTheme(newTheme)
}
return <div className='z-10 p-1 duration-200 mr-2 h-12 text-xl cursor-pointer dark:text-gray-300 '>
<i id='darkModeButton' className={'fa p-2.5 hover:scale-125 transform duration-200 ' + (userTheme === 'dark' ? 'fa-sun-o' : 'fa-moon-o')}
onClick={handleChangeDarkMode} />
</div>
}
export default DarkModeButtonBaseLayout.js
import { useTheme } from '@/lib/theme'
const BaseLayout = ({children}) => {
const { theme } = useTheme()
return (
<div id='wrapper' className={`${theme}`}>
{children}
</div>
)
}
export default BaseLayout🤗总结归纳
服务端解决不了,那就客户端解决。相关代码可以在我的Github项目中查看。
行动建议
我在使用NextJS+NotionAPI开发我的独立博客站,欢迎您在底部评论区留言,一起交流~
参考
‣
GithubIs sues: https://github.com/vercel/next.js/issues/2252
- Author:tangly1024
- URL:https://tangly1024.com/article/nextjs-cookie-localStorage-darkMode
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts :
Tags:
开发
NextJS
ReactJS
