摘要
我有两个状态:isLogged
和counter
。isLogged
是一个布尔,用户可以将其设置为true或false,这样做时,如果isLogged
设置为true,用户可以访问某些页面。counter
只是一个简单的int,用户可以在其中递增/递减。如果两个状态的值发生变化,它们都会保存在sessionStorage
上;在init上,我运行了一个分派,从sessionstorage
中获取这两个值。isLogged
的默认值为false
,counter
为0
。
问题
举个例子,我们有这样的状态值:isLogged = true
counter = 4
如果我尝试调用increment
操作,那么现在的值将是:
isLogged = false
counter = 5
如您所见,它将isLogged
重置为其默认值。然而,当我在Chrome上查看sessionstorage
面板时,它显示:{isLogged: true, counter: 5}
,所以它仍然保存sessonstorage
上的值,那里的一切似乎都很好。然而,在应用程序本身上,它表示isLogged
现在是false
,用户即使出于某种原因没有注销,也无法再访问某些页面。
奇怪的是,如果我刷新页面,现在的状态是:
isLogged = true
counter = 5
(当然,数据已经从sessionstorage
中提取(但如果我现在将isLogged
切换到false
,它也会将counter
重置为0
:
isLogged = false
counter = 0
所以问题是,当我调用调度/操作来修改某个状态时,所有其他状态都会被重置。
代码
src/actions/index.js
export const increment = (num) => {
return {
type: 'INCREMENT',
payload: num
}
}
export const decrement = () => {
return {
type: 'DECREMENT'
}
}
export const get_data = () => {
return {
type: 'GET'
}
}
export const signin = () => {
return {
type: 'SIGN_IN'
}
}
export const signout = () => {
return {
type: 'SIGN_OUT'
}
}
export const getlogged = () => {
return {
type: 'GET'
}
}
src/reducers/counter.js
const counterReducer = (state = 0, action) => {
switch(action.type) {
case 'INCREMENT':
state += action.payload
saveCounter(state)
return state
case 'DECREMENT':
state -= 1
saveCounter(state)
return state
case 'GET':
state = getCounter()
return state
default:
return 0
}
}
const saveCounter = (state) => {
const data = {
counter: state
}
sessionStorage.setItem("data", JSON.stringify(data))
}
const getCounter = () => {
if (sessionStorage.getItem("data") != null) {
const data = JSON.parse(sessionStorage.getItem("data"))
return data["counter"]
}
else {
return 0
}
}
export default counterReducer
src/reducers/isLogged.js
const loggedReducer = (state = false, action) => {
switch(action.type) {
case 'SIGN_IN':
state = true
saveLogged(state)
return state
case 'SIGN_OUT':
state = false
saveLogged(state)
return state
case 'GET':
state = getLogged()
return state
default:
return false
}
}
const saveLogged = (state) => {
const data = {isLogged: state}
sessionStorage.setItem("logged", JSON.stringify(data))
}
const getLogged = () => {
if (sessionStorage.getItem("logged") != null) {
const data = JSON.parse(sessionStorage.getItem("logged"))
return data["isLogged"]
}
else {
return false
}
}
export default loggedReducer
我把它称为这样一个组件:
useEffect(() => {
getCounter()
}, [])
const counter = useSelector(state => state.counter)
const dispatch = useDispatch()
const getCounter = () => {
dispatch(get_data())
}
return (
<div className="container-fluid mt-3">
<p className="text-white">Counter: {counter}</p>
<button onClick={() => dispatch(increment(4))} className="btn btn-primary">+</button>
<button onClick={() => dispatch(decrement())} className="btn btn-danger">-</button>
</div>
)
问题是,在两个减速器中,您都在默认情况下返回默认状态。这意味着每个未处理的操作都将重置状态。
例如,当您调度增量操作时,它在reducer中处于默认状态,并将状态设置为false。
默认情况应该只是简单地返回状态不变。
除此之外,您的useEffect似乎有点危险,因为getCounter在每次渲染时都会更改,所以每次都会调用它。
如果你想在localStorage中保存一些东西,我还建议你使用redux的中间件。reducer应该是一个没有副作用的函数,所以你不尊重这里的规则。您也不应该通过操作从localStorage读取,而是在创建存储时从localStorage中读取。