[英]Too many re-renders. Using switch statement with useState()
I have an ErrorBox component that is purely displaying the error with the specified attributes.我有一个 ErrorBox 组件,它纯粹显示具有指定属性的错误。 The expected output should be that depending on the
ErrorReason
it will display the associated color, icon and info预期的输出应该是根据
ErrorReason
它将显示关联的颜色、图标和信息
const ErrorBox = ({ ErrorReason }) => {
const [status, setStatus] = useState({})
switch (ErrorReason) {
case "wrong-password":
setStatus({
icon: "lock",
info: "Incorrect password",
color: "#fff"
});
break;
case "invalid-email":
setStatus({
icon: "cross",
info: "Invalid email",
color: "#000"
});
break;
case "too-many-request":
setStatus({
icon: "user",
info: "Too many incorrect requests",
color: "#bbb"
});
break;
}
return (
<div >
<Icon
type={status.icon}
style={{ color: `${status.color}` }}
/>
{status.info}
</div>
);
};
The problem is that you're starting with the state {}
and then immediately modifying it.问题是您从状态
{}
,然后立即修改它。
You don't need to want state here at all.你根本不需要状态在这里。 Just use the error reason:
只需使用错误原因:
const ErrorBox = ({ ErrorReason }) => {
let icon, info, color;
switch (ErrorReason) {
case "wrong-password":
icon = "lock";
info = "Incorrect password";
color = "#fff";
break;
case "invalid-email":
icon = "cross";
info = "Invalid email";
color = "#000";
break;
case "too-many-request":
icon = "user";
info = "Too many incorrect requests";
color = "#bbb";
break;
default:
// Must throw here
throw new Error(`Invalid ErrorReason: ${ErrorReason}`);
}
return (
<div >
<Icon
type={icon}
style={{ color: `${color}` }}
/>
{info}
</div>
);
};
But if you did need state, you'd do the switch
first and then use the value as the initial value of the state:但是,如果您确实需要状态,则可以先进行
switch
,然后使用该值作为状态的初始值:
// If you needed state for some reason (you don't below)
const ErrorBox = ({ ErrorReason }) => {
let initialStatus;
switch (ErrorReason) {
case "wrong-password":
initialStatus = {
icon: "lock",
info: "Incorrect password",
color: "#fff"
};
break;
case "invalid-email":
initialStatus = {
icon: "cross",
info: "Invalid email",
color: "#000"
};
break;
case "too-many-request":
initialStatus = {
icon: "user",
info: "Too many incorrect requests",
color: "#bbb"
};
break;
default:
// Must throw here
throw new Error(`Invalid ErrorReason: ${ErrorReason}`);
}
const [status, setStatus] = useState(initialStatus);
return (
<div >
<Icon
type={status.icon}
style={{ color: `${status.color}` }}
/>
{status.info}
</div>
);
};
I don't think I'd use a switch
to map the ErrorReason
to error information at all, I'd use a map (or an object created with Object.create(null)
):我认为我根本不会使用
switch
将ErrorReason
映射到错误信息,我会使用映射(或使用Object.create(null)
创建的对象):
const statusInfoMap = new Map([
[
"wrong-password",
{
icon: "lock",
info: "Incorrect password",
color: "#fff"
}
],
[
"invalid-email",
{
icon: "cross",
info: "Invalid email",
color: "#000"
}
],
[
"too-many-request",
{
icon: "user",
info: "Too many incorrect requests",
color: "#bbb"
}
]
]);
Then the component is just:那么组件就是:
const ErrorBox = ({ ErrorReason }) => {
const status = statusInfoMap.get(ErrorReason);
if (!status) {
throw new Error(`Invalid ErrorReason: ${ErrorReason}`);
}
const {icon, color, info} = status;
return (
<div >
<Icon
type={icon}
style={{ color: `${color}` }}
/>
{info}
</div>
);
};
Live Example:现场示例:
const {useState, useCallback} = React; const statusInfoMap = new Map([ [ "wrong-password", { icon: "lock", info: "Incorrect password", color: "#fff" } ], [ "invalid-email", { icon: "cross", info: "Invalid email", color: "#000" } ], [ "too-many-request", { icon: "user", info: "Too many incorrect requests", color: "#bbb" } ] ]); const ErrorBox = ({ ErrorReason }) => { const status = statusInfoMap.get(ErrorReason); if (!status) { throw new Error(`Invalid ErrorReason: ${ErrorReason}`); } const {icon, color, info} = status; return ( <div > icon: {icon}, color: {color}, info: {info} </div> ); }; const errors = [ "wrong-password", "invalid-email", "too-many-request", ]; const Example = () => { const [index, setIndex] = useState(0); const error = errors[index]; const onClick = useCallback(() => { setIndex(index + 1); }, [index]); return ( <div> <ErrorBox ErrorReason={error} /> {index < errors.length - 1 ? <input type="button" value="Next" onClick={onClick} /> : <input type="button" value="Start Again" onClick={() => setIndex(0)} /> } </div> ); }; ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
Or if you need state for something you haven't shown:或者,如果您需要未显示的内容的状态:
const ErrorBox = ({ ErrorReason }) => {
const initialStatus = statusInfoMap.get(ErrorReason);
if (!initialStatus) {
throw new Error(`Invalid ErrorReason: ${ErrorReason}`);
}
const [status, setStatus] = useState(initialStatus);
const {icon, color, info} = status;
return (
<div >
<Icon
type={icon}
style={{ color: `${color}` }}
/>
{info}
</div>
);
};
You should perform state update only when ErrorReason
changes.仅当
ErrorReason
更改时才应执行状态更新。 In this scenario use useEffect
hook and add ErrorReason
as dependency.在这种情况下,使用
useEffect
钩子并添加ErrorReason
作为依赖项。
useEffect(() => {
switch (ErrorReason) {
case "wrong-password":
setStatus({
icon: "lock",
info: "Incorrect password",
color: "#fff"
});
break;
case "invalid-email":
setStatus({
icon: "cross",
info: "Invalid email",
color: "#000"
});
break;
case "too-many-request":
setStatus({
icon: "user",
info: "Too many incorrect requests",
color: "#bbb"
});
break;
}
}, [ErrorReason])
Update: To avoid local state and variables.更新:避免局部状态和变量。
const ErrorBox = ({ ErrorReason }) => {
const getData = () => {
switch (ErrorReason) {
case "wrong-password":
return ({
icon: "lock",
info: "Incorrect password",
color: "#fff"
});
case "invalid-email":
return ({
icon: "cross",
info: "Invalid email",
color: "#000"
});
case "too-many-request":
return ({
icon: "user",
info: "Too many incorrect requests",
color: "#bbb"
});
}}
return (
<div >
<Icon
type={status.icon}
style={{ color: `${status.color}` }}
/>
{getData().info}
</div>
);
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.