【问题标题】:How to handle state using Redux with periodical updates and React Hooks?如何使用带有定期更新和 React Hooks 的 Redux 处理状态?
【发布时间】:2020-02-17 03:58:08
【问题描述】:

我的用例

我刚开始使用带有 Hooks 和 Redux 的 React (Native),并且在理解我的用例的状态更新概念的某些部分时遇到了一些问题。我目前正在开发一个应该每整分钟更新一次数据的 React Native 应用程序。所以如果用户在11h:31m:27s 处进入应用程序,

  1. 应该显示初始状态,然后
  2. setTimeout 处理第一次更新,偏移量达到整分钟(在这种情况下,33s 达到 11h:32m:00s
  3. setInterval 从现在开始处理数据的每分钟更新。

我的问题

目前,使用下面的代码,reducers.js 文件中的console.log("Reducer Fires!") 每分钟都会被触发一次(例如,第一分钟只触发一次,然后在第二分钟触发两次,依此类推)。所以我觉得我在如何处理我的数据状态以及setInterval()setTimeout() 逻辑方面仍然做错了。有人可以在下面查看我的代码并指出我正在做的错误吗?

我的代码(到目前为止)

一些假人data

export const DATA = [
    {"id": 1, "myAttr": 0},
    {"id": 2, "myAttr": 4},
    {"id": 3, "myAttr": 8},
    {"id": 4, "myAttr": 12},
]

带有 redux 存储的 App.js 文件:

import React from 'react';
import { createStore, combineReducers } from "redux";
import { Provider } from "react-redux";
import { View } from 'react-native';

// Components
import MyComponent from "./components/MyComponent";
import dataReducer from "./store/reducers";

//Create Redux store
const rootReducer = combineReducers({
  mydata: dataReducer
});

const store = createStore(rootReducer);

export default function App() {

  return (
    <Provider store={store} >
      <View>
        <MyComponent />
      </View>
    </Provider>
  );
}

actions.js 文件存储了我的 Redux 操作:

//Action to update the data
export const UPDATE_DATA = "UPDATE_DATA";

export const updateData = () => {
    return { type: UPDATE_DATA }
}

reducers.js 文件来存储减速器:

import { DATA } from "../data/data";
import { UPDATE_DATA } from "./actions";

// Initial state when app launches
const initState = {
    data: DATA
}

const dataReducer = (state = initState, action) => {
    switch (action.type) {
        case UPDATE_DATA:
            //Update an attribute in each object of the data array

            const updatedData = state.data.map((i) => {
                const newMyAttr = i.myAttr + 1;
                return { ...i, myAttr: newMyAttr }
            }
            )

            console.log("Reducer Fires!");
            return { ...state, data: updatedData }

        default:
            return state;
    }
};

export default dataReducer;

我正在尝试更新状态的 component

import React, { useEffect, useCallback } from "react";
import { useSelector, useDispatch } from "react-redux";
import { Text, View } from 'react-native';

const MyComponent = (props) => {
    const myData = useSelector(state => state.mydata.data);

    let start = new Date();
    const fullMinuteOffset = (60 - start.getSeconds()) * 1000;

    const dispatch = useDispatch();

    const saveData = useCallback(() => {
        dispatch(updateData())
    }, [dispatch]);

    useEffect(() => {
        const timer = setTimeout(() => {
            saveData()
            const interval = setInterval(() => {
                saveData()
            }, 60000)

            return () => clearInterval(interval);
        }, fullMinuteOffset);

        return () => clearTimeout(timer);
    }, [saveData, fullMinuteOffset]);

    return(
        <View>
            <Text>{myData[0].myAttr}</Text>
        </View>
    );
};

export default MyComponent;

【问题讨论】:

    标签: javascript reactjs react-native redux react-redux


    【解决方案1】:

    组件每次渲染时都会有一个新的 fullOffserMinute 值,它是 useEffect 的依赖项,因此注册了一个新的间隔调用。

    这是您的代码的简化工作示例:

    https://codesandbox.io/s/jolly-panini-k35s1?fontsize=14&hidenavigation=1&theme=dark

      // the relevant part of it
      let start = new Date();
      let [counter, setCounter] = useState(0);
      const fullMinuteOffset = (60 - start.getSeconds()) * 1000;
    
      function timerAction() {
        setCounter(counter => counter + 1);
      };
    
      useEffect(() => {
        console.log("-- use effect --");
        const timer = setTimeout(() => {
          console.log("save data timeout");
          timerAction();
          const interval = setInterval(() => {
            console.log("save data interval");
            timerAction();
          }, 5000);
    
          return () => clearInterval(interval);
        }, fullMinuteOffset);
    
        return () => clearTimeout(timer);
      }, []);
    

    如果您要定期更新本地状态,还应该阅读此处的答案: State not updating when using React state hook within setInterval

    【讨论】:

    • 谢谢。当我按照您编写的方式使用代码时,我的多次打印问题就消失了。
    【解决方案2】:

    如果将 useEffect 依赖项更改为以下内容会发生什么:[saveTime, fullMinuteOffset] -> 到此[]。似乎每次 useEffect 调用的组件更新可能会注册更多间隔

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 2020-01-29
      • 2020-11-25
      • 2022-01-18
      • 1970-01-01
      • 1970-01-01
      • 2020-08-07
      • 2020-06-19
      • 2019-08-08
      相关资源
      最近更新 更多