如何优雅地使用react做一个wordle小游戏?
我用reat + tailwindcss
实现了该游戏,但是比较纠结什么什么时候该使用React.useCallback
,自定义的hooks是否合理?
我写了一个自定义的hook,用来实现数据持久化(刷新之后仍可以保持刷新之前的游戏状态)
- 这里的
name
,initial
永远都不会变化。 初始状态先从
localstorage
中获取,然后调用initial
函数(包装了hook
返回的set
函数。- 期望这个effect只会在初始加载的时候调用一次。
为什么不直接在
React.useState(() => { window.localstore...})
获取初始状态呢?- 因为这是一个next项目,在服务端渲染的时候是没有
window
这个对象的。 - 避免本地的初次渲染和服务端的初次渲染不匹配。
- 因为这是一个next项目,在服务端渲染的时候是没有
- 当状态改变的时候,就更新
localstorage
中的值。
- 当状态改变的时候,就更新
// src/hooks/useLocalStore.js
function useLocalStore(state, name, initial) {
React.useEffect(() => {
let store = window.localStorage.getItem(name);
if (store) initial(JSON.parse(store));
}, [name, initial]);
React.useEffect(() => {
window.localStorage.setItem(name, JSON.stringify(state));
}, [name, state]);
}
自定义hook的时候,需要将函数先用React.useCallback
"包"起来。否则的话,上面提到的预期就达不到了。每次渲染的时候都会产生一个新的intial
,effect
每次都会执行。
// src/hooks/useLocalStore.js
....
import useLocalStore from "./useLocalStore";
function useGameState(notify, statistic) {
const [gameState, dispatch] = React.useReducer(reducer, initialState);
const initial = React.useCallback(
(state) => dispatch({ type: "load-state", state: state }),
[]
);
useLocalStore(gameState, "gameState", initial);
....
当自定义的hooks
需要传入一个函数的时候,我们首先需要考虑是否需要将这个函数用React.useCallback
"包"起来呢?其实,我们也可以不考虑,都用React.useCallback
包起来应该就万事大吉了。最后在我的项目中到处可见React.useCallack
,总觉得有些奇怪,是我自定义hooks有问题吗?
另外自定义hook返回的值又作为参数传给了另一个hook,这样写合理吗?
解释下面代码:
- 当想要改变游戏的状态时,可能需要给出提示,如"游戏进行中,不能开始新一轮游戏"、"必须包含字母S"..。
- 当一局游戏结束的时候,需要提示“胜利”或者“失败”,并将当前局的获胜情况记录到gameStatistic状态中。
所以才试图将
useNotification
和useGameStatistc
这两个自定义hook
的返回值传给另一个useGameState
这个自定义hook
。// src/app/page.js import React from "react"; import useGameState from "@/hooks/useGameState"; import useNotification from "@/hooks/useNotification"; import useGameStatistic from "@/hooks/useGameStatistic"; export default function Home() { const [message, notify] = useNotification(); const [gameStatistic, statistic] = useGameStatistic(); const [gameState, startGame, changeGameStateBasedOnKey, toggleHardMode] = useGameState(notify, statistic); ....
附: