当前位置: 首页 > 知识库问答 >
问题:

ReactJS-更新状态会导致延迟

锺离宸
2023-03-14

描述

我有一个小应用程序,它使用useCallback()hook更新状态,但每次更新时,都会导致页面延迟。我指的是实际的延迟,而不仅仅是“等待异步setState()”延迟。

我的理论是,更新状态会重新呈现太多的组件,因为如果我将状态减少到更少的值,滞后就会消失。

从本质上说,我担心我更新状态的方式没有隔离我想要的值。

密码

我将回购加载到CodeSandbox:https://codesandbox.io/s/long-forest-y9cdj?file=/src/App.js

要点如下:

>

  • 页面上的按钮有一个onClark,从App.js

    App.js中,我们生成handle点击回调,调用减速器

    reducer.js中,"UPDATE_COUNT"大小写更新状态以设置正确的值。

    重现问题

    乱七八糟,以某种高节奏点击一些按钮,你应该会经历一些滞后。你知道,导致按钮动画冻结,光标停留在“指针手指”模型中的滞后类型。

    问题

    状态更新是否可以减少这种延迟?

  • 共有1个答案

    盖绪
    2023-03-14

    我发现唯一奇怪的是,您在组件中声明了您的useStyles钩子,因此每个渲染周期都创建了新的样式。将这些移到组件之外。

    例子:

    一个pp.js

    const useStyles = makeStyles((theme) => ({
        root: {
            flexGrow: 1
        },
        paper: {
            padding: theme.spacing(0),
            textAlign: "center",
            color: theme.palette.text.primary,
            backgroundColor: theme.palette.background
        }
    }));
    
    function App() {
      const classes = useStyles();
    
      const { state, dispatch } = React.useContext(MainContext);
    
      const handleClick = useCallback(
        (areaName, monsterName, newCount) => {
          newCount = newCount > 10 ? 10 : newCount;
          newCount = newCount < 0 ? 0 : newCount;
    
          dispatch({
            type: "UPDATE_COUNT",
            area: areaName,
            monster: monsterName,
            count: newCount
          });
        },
        [dispatch]
      );
    
      const areaObjects = Object.entries(state).map(([area, monster]) => {
        const monsters = Object.entries(monster).map(([monsterName, count]) => (
          <Grid item xs={12} key={monsterName}>
            <Monster
              area={area}
              name={monsterName}
              count={count}
              handleClick={handleClick}
            />
          </Grid>
        ));
    
        return (
          <Grid item xs={12} sm={6} md={4} lg={3} xl={2} key={area}>
            <Paper className={classes.paper}>
              <Grid item xs={12}>
                <h3>{area}</h3>
              </Grid>
              {monsters}
            </Paper>
          </Grid>
        );
      });
    
      return (
        <div className={classes.root} id={"app-container"} key={"app-container"}>
          <Grid container spacing={0}>
            {areaObjects}
          </Grid>
        </div>
      );
    }
    

    Monster.js

    const useStyles = makeStyles((theme) => ({
      root: {
        flexGrow: 1
      },
      addButtonContainer: {
        backgroundColor: "lightblue"
      },
      subtractButtonContainer: {
        backgroundColor: "lightyellow"
      },
      maxButtonContainer: {
        backgroundColor: "lightgreen"
      },
      monsterName: {
        textAlign: "center"
      },
      row: {
        backgroundColor: "lightgray"
      },
      rowSuccess: {
        backgroundColor: "lightgreen"
      }
    }));
    
    export default function Monster({ area, name, count, handleClick }) {
      const handleIncrement = (areaName, monsterName) => {
        handleClick(areaName, monsterName, count + 1);
      };
    
      const handleDecrement = (areaName, monsterName) => {
        handleClick(areaName, monsterName, count - 1);
      };
    
      const handleMaxout = (areaName, monsterName) => {
        handleClick(areaName, monsterName, 10);
      };
    
      const classes = useStyles();
      const rowClass = count === 10 ? classes.rowSuccess : classes.row;
    
      return (
        <Grid container item className={rowClass}>
          <Grid item xs={7} className={classes.monsterName}>
            {name}
          </Grid>
          <Grid item xs={1} className={classes.maxButtonContainer}>
            <IconButton
              color={"primary"}
              variant={"contained"}
              size={"small"}
              onClick={() => handleMaxout(area, name)}
            >
              <ArrowUpward fontSize={"small"} />
            </IconButton>
          </Grid>
          <Grid item xs={1} className={classes.addButtonContainer}>
            <IconButton
              color={"primary"}
              variant={"contained"}
              size={"small"}
              onClick={() => handleIncrement(area, name)}
            >
              <Add fontSize={"small"} />
            </IconButton>
          </Grid>
          <Grid item xs={2}>
            {count}
          </Grid>
          <Grid item xs={1} className={classes.subtractButtonContainer}>
            <IconButton
              color={"secondary"}
              variant={"contained"}
              size={"small"}
              onClick={() => handleDecrement(area, name)}
            >
              <Remove fontSize={"small"} />
            </IconButton>
          </Grid>
        </Grid>
      );
    }
    

    我还记下了上下文提供的state,尽管我不完全认为这一部分是必要的。

    index.js
    
    import React, { useMemo } from "react";
    
    import initialState from "./initialState";
    import reducer from "./reducer";
    
    const MainContext = React.createContext();
    
    function MainContextProvider(props) {
      const [state, dispatch] = React.useReducer(reducer, initialState);
      const value = useMemo(() => ({ state, dispatch }), [state]);
    
      return (
        <MainContext.Provider value={value}>{props.children}</MainContext.Provider>
      );
    }
    
    const MainContextConsumer = MainContext.Consumer;
    
    export { MainContext, MainContextProvider, MainContextConsumer };
    
     类似资料:
    • 问题内容: constructor(){ super(); this.state = { address: { street:null, city:null, postalCode: null } }; } postalCodeChange(e){ this.setState.address.postalCode = e.target.value; console.log(this.state);

    • 问题内容: 我觉得我已经在阳光下尝试了所有东西,但是一定缺少一些非常明显的东西。在下面,我试图将一个新项目推入数组并更新状态,但是无论我做什么,状态都不会从初始数组更改。 当我console.log newListItems时,新项目就包括在内,因此到目前为止所有工作都在进行,它是不会更新的实际状态。我想念什么? addItem方法: 我也没有在控制台中收到任何错误消息。 完整代码: 问题答案:

    • 我刚刚开始使用ReactJs开发,并一直遵循serverless-stack.com教程。我已经准备好扩展应用程序并创建一个模板,带有n个子组件,但是在管理孙子组件之间的用户会话时遇到了麻烦。 我有管理用户会话的App.js。但是我在孙子组件中有我的注销按钮,我无法让它调用App.js signOut()函数。 App.js 我的布局组件有一系列不同的组件,如页眉、页脚、导航等。。 最后,我的Na

    • 使用Kubernetes 1.12.6-gke。7或更高版本可以创建ManagedCertificate,然后从向Internet公开服务的入口资源引用该证书。 运行kubectl描述管理证书证书名称首先指示证书处于配置状态,但最终转到FailedNotViable。 尽管使用静态IP和DNS可以很好地解析上述服务的http版本,但所有ManagedCertificate最终都会处于“状态:Fai

    • 我是新来的反应。我被困在这件事上,真的很感激你的帮助! 父组件将把一个数组传递到这个子组件中。当我console.log(this.props.repairs)时,它显示了一个4的数组。每当传入修复数组时,我都试图更新this.state.SortedDataList。console.log(this.state)仍然将sortedDataList显示为空数组。 我做错了什么?非常感谢,谢谢你的帮

    • 我试图了解如何构建具有不同"页面"或"视图"的ReactJS应用程序。 我将以下组件作为我的基础应用程序,并且我正在React状态中使用currentState属性在视图中的活动组件之间切换。 它执行此任务,但在启动dataLoaded回调时,组件从不接收更新的recipes数组。 如何根据应用程序中的更新状态更新道具? 还是我处理这整件事的方式错了?