描述
我有一个小应用程序,它使用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"
大小写更新状态以设置正确的值。
重现问题
乱七八糟,以某种高节奏点击一些按钮,你应该会经历一些滞后。你知道,导致按钮动画冻结,光标停留在“指针手指”模型中的滞后类型。
问题
状态更新是否可以减少这种延迟?
我发现唯一奇怪的是,您在组件中声明了您的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数组。 如何根据应用程序中的更新状态更新道具? 还是我处理这整件事的方式错了?