首页 > 解决方案 > redux dispatch 将其他状态重置为默认值

问题描述

概括

我有 2 个状态:isLoggedcounter. isLogged是一个布尔值,用户可以将其设置为 true 或 false,这样做用户可以访问 ifisLogged设置为 true 的某些页面。这counter只是一个简单的 int,用户可以在其中递增/递减它。sessionStorage如果它们的值发生变化,这两种状态都会被保存;在初始化时,我运行了一个调度以从sessionstorage. isLogged的默认值为false和。 counter0

问题

假设我们有这个状态值:
isLogged = true
counter = 4

如果我尝试调用一个increment动作,现在的值将是:

isLogged = false
counter = 5

如您所见,它将 重置isLogged为其默认值。但是,当我sessionstorage在 Chrome 上查看面板时,它会说:{isLogged: true, counter: 5}所以它仍在保存值,sessonstorage并且那里的一切似乎都工作正常。但是在应用程序本身上,它说isLogged现在是现在false,即使他出于某种原因没有注销,用户也无法再访问某些页面。

奇怪的是,如果我刷新页面,现在的状态是:

isLogged = true
counter = 5

(当然数据是从 中获取的sessionstorage)但是如果我现在切换isLoggedfalse,它也会重置counter0

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>
)

标签: javascriptreactjsreact-redux

解决方案


问题在于,在您的两个减速器中,您在默认情况下都返回了默认状态。这意味着每个未处理的操作都会重置状态。

例如,当您调度一个增量操作时,它会在您的 reducer 中进入默认状态并将状态设置为 false。

默认情况下应该简单地返回未更改的状态。


除此之外,你的 useEffect 似乎有点危险,因为 getCounter 在每次渲染时都会发生变化,每次都会调用它。

如果你想在 localStorage 中保存一些东西,我还建议你使用 redux 的中间件。reducer 应该是一个没有副作用的函数,所以你不尊重这里的规则。您也不应该通过操作从 localStorage 读取,而是在创建商店时从 localStorage 读取。


推荐阅读