usereducer - 仅将某些状态保存到会话存储?
usereducer - only persisting certain state to session storage?
我有一个关于动词变位的测验。您将有关您想要的结合的过滤器选项发送到后端,它会发回必要的信息。在我的测验页面中,我有一个 usereducer 将管理所有这些状态。我希望将结合数据以及当前结合(因此是当前问题)索引保存到会话存储中。
但是,我不希望错误状态、用户输入、应该重定向变量(如果用户未指定任何过滤器选项时将重定向)等数据被保留,因为如果您刷新页面,您不希望错误消息持续存在,或者至少我觉得这不是我想要的。
关键是,这些状态不能在不同的 reducer 中分离,因为我想在同一操作中更改一些本地状态和持久化状态。
我想出了一个非常简单的解决方案,就是将我想要持久化的状态放在一个名为 persisted 的对象中:
{
persisted: {
conjugations: [...],
currentConjugationIndex: 2,
numOfCorrectAnswers: 1,
numOfIncorrectAnswers: 3
},
userAnswer: "habló",
error: ""
...
}
这意味着所有这些状态都可以在一个 reducer 中,然后只持久化那个持久化的对象而不是整个事物。我只是觉得我还没有看到其他人有这个问题,这让我怀疑我是否应该做其他事情。意见?
编辑:
到目前为止我的代码:
const useQuizReducer = () => {
const persistedState = JSON.parse(sessionStorage.getItem("quiz"));
const [state, dispatch] = useImmerReducer(
reducer,
persistedState
? {...initialStates, persisted: persistedState}
: initialStates
);
useEffect(() => {
sessionStorage.setItem("quiz", JSON.stringify(state.persisted));
}, [state.persisted])
const {persisted, ...rest} = state;
return [{...persisted, ...rest}, dispatch];
}
您混淆了减速器中的不同问题。我建议你把它们分开。这通常会使您的代码更加清晰,并且 - 作为奖励 - 减少了隐藏在复杂丛林中的错误的机会。
- 首要关注点:客户端运行时状态
- 第二个问题:页面重新加载之间的状态持久性
您有两个不同的关注点:根据经验,您添加了两个不同的代码部分,每个关注点一个。
这是一个如何做到这一点的想法:
// the reducer only handles your first concern
const [state, dispatch] = useReducer(reducer, emptyInitialState, tryReadSessionStorage);
// this handles your second concern
useEffect(() => tryUpdateSessionStorage(state), [state]);
// e.g. in some other file
const tryUpdateSessionStorage = ({
conjugations,
currentConjugationIndex,
numOfCorrectAnswers,
numOfIncorrectAnswers,
}) => {
try {
sessionStorage.setItem("quiz", JSON.stringify({
conjugations,
currentConjugationIndex,
numOfCorrectAnswers,
numOfIncorrectAnswers,
}));
} catch (exception) {}
}
const tryReadSessionStorage = (emptyInitialState) => {
let persistedState;
try {
persistedState = JSON.parse(sessionStorage.getItem("quiz"));
} catch (exception) {}
return { ...emptyInitialState, ...persistedState };
}
我有一个关于动词变位的测验。您将有关您想要的结合的过滤器选项发送到后端,它会发回必要的信息。在我的测验页面中,我有一个 usereducer 将管理所有这些状态。我希望将结合数据以及当前结合(因此是当前问题)索引保存到会话存储中。
但是,我不希望错误状态、用户输入、应该重定向变量(如果用户未指定任何过滤器选项时将重定向)等数据被保留,因为如果您刷新页面,您不希望错误消息持续存在,或者至少我觉得这不是我想要的。
关键是,这些状态不能在不同的 reducer 中分离,因为我想在同一操作中更改一些本地状态和持久化状态。
我想出了一个非常简单的解决方案,就是将我想要持久化的状态放在一个名为 persisted 的对象中:
{
persisted: {
conjugations: [...],
currentConjugationIndex: 2,
numOfCorrectAnswers: 1,
numOfIncorrectAnswers: 3
},
userAnswer: "habló",
error: ""
...
}
这意味着所有这些状态都可以在一个 reducer 中,然后只持久化那个持久化的对象而不是整个事物。我只是觉得我还没有看到其他人有这个问题,这让我怀疑我是否应该做其他事情。意见?
编辑:
到目前为止我的代码:
const useQuizReducer = () => {
const persistedState = JSON.parse(sessionStorage.getItem("quiz"));
const [state, dispatch] = useImmerReducer(
reducer,
persistedState
? {...initialStates, persisted: persistedState}
: initialStates
);
useEffect(() => {
sessionStorage.setItem("quiz", JSON.stringify(state.persisted));
}, [state.persisted])
const {persisted, ...rest} = state;
return [{...persisted, ...rest}, dispatch];
}
您混淆了减速器中的不同问题。我建议你把它们分开。这通常会使您的代码更加清晰,并且 - 作为奖励 - 减少了隐藏在复杂丛林中的错误的机会。
- 首要关注点:客户端运行时状态
- 第二个问题:页面重新加载之间的状态持久性
您有两个不同的关注点:根据经验,您添加了两个不同的代码部分,每个关注点一个。 这是一个如何做到这一点的想法:
// the reducer only handles your first concern
const [state, dispatch] = useReducer(reducer, emptyInitialState, tryReadSessionStorage);
// this handles your second concern
useEffect(() => tryUpdateSessionStorage(state), [state]);
// e.g. in some other file
const tryUpdateSessionStorage = ({
conjugations,
currentConjugationIndex,
numOfCorrectAnswers,
numOfIncorrectAnswers,
}) => {
try {
sessionStorage.setItem("quiz", JSON.stringify({
conjugations,
currentConjugationIndex,
numOfCorrectAnswers,
numOfIncorrectAnswers,
}));
} catch (exception) {}
}
const tryReadSessionStorage = (emptyInitialState) => {
let persistedState;
try {
persistedState = JSON.parse(sessionStorage.getItem("quiz"));
} catch (exception) {}
return { ...emptyInitialState, ...persistedState };
}