setInterval()中的React-Redux - State值不正确

u2nhd7ah  于 2023-06-30  发布在  React
关注(0)|答案(2)|浏览(151)

react-redux / react-toolkit有问题。我有一个叫做todos的状态。此状态正确填充了3个项目,如您在这里看到的:

这是我的todo slice的代码:

import { createSlice } from '@reduxjs/toolkit';

const initialState = {
  value: []
};

export const todoSlice = createSlice({
  name: 'todos',
  initialState,
  reducers: {
    setTodos: (state, action) => {
      state.value = action.payload
    },
  },
});

export const { setTodos } = todoSlice.actions;

export default todoSlice.reducer;

我正在使用Indexed Db在本地存储todos。因此,我有一个间隔(在我的app.container.js中有setInterval,检查todos是否需要重新加载。

function App(props) {

    const [interval, setInterval] = useState(null);
    const dispatch = useDispatch();
    const todos = useSelector((state) => state.todos.value);
    const { loadTodos, loadTodosFromIndexedDB } = useTodo();
    //...

    useEffect(() => {
        //...
        initializeInterval();
        //...
    },[]);

    async function initializeInterval() {
        setInterval(window.setInterval(async () => {
                await getTodosFromIndexedDB();
            },3000)
        );
    }

    async function getTodosFromIndexedDB() {
        let todosFromIndexedDb = await loadTodosFromIndexedDB();
        if(todos?.length !== todosFromIndexedDb?.length && !Utils.isNullOrUndefined(todosFromIndexedDb)) {
            dispatch(setTodos(todosFromIndexedDb));
        }
        //...
    }

    return (
        //...
    )
}

问题是,在函数getTodosFromIndexedDB()中,todos的值类似于初始值todos的空数组([])。

这会导致更新每3秒被触发一次,但此函数中的todos值保持在空数组([])上。正在触发的更新提供了正确的3个待办事项:

getTodosFromIndexedDB()函数中todos的值不正确是什么原因?这是异步问题还是因为不同的作用域(window.setInterval)?

stszievb

stszievb1#

在第一次呈现时,您将getTodosFromIndexedDB函数注册为一个interval,它作为一个闭包,其作用域是组件执行的变量。你可以使用ref来解决这个问题:

const todos = useSelector((state) => state.todos.value);
const todosRef = useRef(todos)
useEffect(() => { todosRef.current = todos })

// in `getTodosFromIndexedDB`, access `todosRef.current` instead of `todos`
b4wnujal

b4wnujal2#

我发布这个作为一个答案,以获得更多的空间,我还没有测试,但我觉得最初todo是一个空数组,当你创建这个函数时,它存储为空数组,每次设置间隔运行时,它使用相同的todo值。这就是为什么它不能工作,但是您可以使用useCallback在每次todos值更改时重新创建这个函数

async function getTodosFromIndexedDB() {
        let todosFromIndexedDb = await loadTodosFromIndexedDB();
        if(todos?.length !== todosFromIndexedDb?.length && !Utils.isNullOrUndefined(todosFromIndexedDb)) {
            dispatch(setTodos(todosFromIndexedDb));
        }
        //...
    }

更新码

function App(props) {

    const [interval, setInterval] = useState(null);
    const dispatch = useDispatch();
    const todos = useSelector((state) => state.todos.value);
    const { loadTodos, loadTodosFromIndexedDB } = useTodo();
    const getTodosFromIndexDb = useCallback(  async () => {
        let todosFromIndexedDb = await loadTodosFromIndexedDB();
        if(todos?.length !== todosFromIndexedDb?.length && !Utils.isNullOrUndefined(todosFromIndexedDb)) {
            dispatch(setTodos(todosFromIndexedDb));
        }
    },[todos])
    //...

    useEffect(() => {
        //...
        initializeInterval();
        //...
    },[]);

    async function initializeInterval() {
        setInterval(window.setInterval(async () => {
                await getTodosFromIndexedDB();
            },3000)
        );
    }

  

    return (
        //...
    )
}

相关问题