在函数组件中使用 useState hook 的最佳方式?
The best way of the using useState hook in Function Component?
我想显示一个 div 与对象 属性 相关的结果为真或为假。
我使用了一种方法,但我不确定它是最好的方法还是它打开了性能问题。
我正在检查 return 部分循环中的 属性 以避免额外的数组操作。但我认为它会导致额外的渲染。
另一个选项是在 return 部分之外检查 属性。但这会导致额外的数组操作。
哪种方式最适合我?我在下面展示了 2 种不同的实现方式。
选项 1:
const RadioButtonList: FunctionComponent<RadioButtonListProps> = ({ items, changeFilter }) => {
const [showClearIcon, setShowClearIcon] = React.useState(false);
return (
<div className="radio-button-list">
{showClearIcon && <div className="clear-icon">clear</div>}
<ul>
{items.map(item => {
/* this is the area what I'm checking the property */
if (item.selected) {
setShowClearIcon(true);
}
return (
<li key={item.id}>
<label htmlFor={item.text} className="radio">
<span className="input">
<input type="radio" onClick={changeFilter} readOnly />
</span>
</label>
</li>
);
})}
</ul>
</div>
);
};
选项 2:
const RadioButtonList: FunctionComponent<RadioButtonListProps> = ({ items, changeFilter }) => {
const [showClearIcon, setShowClearIcon] = React.useState(false);
/* set in useEffect hook */
useEffect(() => {
if(items.some(item => item.selected)) {
setShowClearIcon(true);
}
}, [items]);
return (
<div className="radio-button-list">
{showClearIcon && <div className="clear-icon">clear</div>}
<ul>
{items.map(item => {
return (
<li key={item.id}>
<label htmlFor={item.text} className="radio">
<span className="input">
<input type="radio" onClick={changeFilter} readOnly />
</span>
</label>
</li>
);
})}
</ul>
</div>
);
};
选项 1 在渲染中排队状态更新 return,不要使用它。
作为副作用,使用选项 2 正确地将更新加入队列。在 React 中,渲染函数被认为是一个纯函数。不要无条件地排队状态更新。
关于性能,迭代数组是O(n)
。迭代一个数组两次还是O(n)
.
建议
showClearIcon
“状态”可能不应该是 React 状态,因为它很容易从 items
属性派生。
Identify the Minimal (but complete) Representation of UI State
Let’s go through each one and figure out which one is state. Ask three
questions about each piece of data:
- Is it passed in from a parent via props? If so, it probably isn’t state.
- Does it remain unchanged over time? If so, it probably isn’t state.
- Can you compute it based on any other state or props in your component? If so, it isn’t state.
因此,只需在本地计算 showClearIcon
值。
const showClearIcon = items.some(item => item.selected);
这个 可以 与 useMemo
挂钩一起记忆,如果需要的话依赖于 items
。
所以,如果你想纯粹看性能,你可以做的是安装反应开发工具 chrome 扩展,然后在你的测试服务器(例如 localhost:3000)中你可以使用chrome 的 f12 菜单中的分析器选项卡,用于检查哪个操作占用更多内存!
这是您可以用于所有优化问题的东西
如果你的目标是渲染 html 组件,应该使用选项 2 (useEffect),记住依赖数组中只包含必需的依赖项(这是为了避免 re-render 和性能相关的问题)。在你的情况下,选项 2 是正确的,它的性能将由 React 本身调整。
看起来showClearIcon
根本不需要是状态原子,而只是a memoized value依赖于items
。
const showClearIcon = React.useMemo(
() => items.some(item => item.selected),
[items],
);
从技术上讲,您可以在没有 useState
和 useEffect
的情况下完成它,并且无需对数组进行两次迭代,请查看下面的示例(它可能不是必需的,但最好知道这也是可能的):
const RadioButtonList: FunctionComponent<RadioButtonListProps> = ({
items,
changeFilter,
}) => {
const renderItems = () => {
let showClearIcon = false;
let markup = (
<ul>
{items.map((item) => {
if (item.selected) {
showClearIcon = true;
}
return (
<li key={item.id}>
<label htmlFor={item.text} className="radio">
<span className="input">
<input type="radio" onClick={changeFilter} readOnly />
</span>
</label>
</li>
);
})}
</ul>
);
return (
<>
{showClearIcon && <div className="clear-icon">clear</div>}
{markup}
</>
);
};
return <div className="radio-button-list">{renderItems()}</div>;
};
简单地创建了一个生成标记的函数。
选项 2 是更好的方法,但是选项 2 你也可以有更好的编码,如下所示,使代码更好更简单
const RadioButtonList: FunctionComponent<RadioButtonListProps> = ({ items, changeFilter }) => {
// as suggested by AKX
const showClearIcon = React.useMemo(
() => items.some(item => item.selected),
[items],
);
/* set in useEffect hook */
useEffect(() => {
if(items.some(item => item.selected)) {
setShowClearIcon(true);
}
}, [items]);
// for displaying row items
const generateRow = ({id, text}) => {
return (
<li key={item.id}>
<label htmlFor={item.text} className="radio">
<span className="input">
<input type="radio" onClick={changeFilter} readOnly />
</span>
</label>
</li>
);
}
return (
<div className="radio-button-list">
{showClearIcon && <div className="clear-icon">clear</div>}
<ul>
{items.map(item => generateRow(item))}
</ul>
</div>
);
};
我想显示一个 div 与对象 属性 相关的结果为真或为假。 我使用了一种方法,但我不确定它是最好的方法还是它打开了性能问题。
我正在检查 return 部分循环中的 属性 以避免额外的数组操作。但我认为它会导致额外的渲染。
另一个选项是在 return 部分之外检查 属性。但这会导致额外的数组操作。
哪种方式最适合我?我在下面展示了 2 种不同的实现方式。
选项 1:
const RadioButtonList: FunctionComponent<RadioButtonListProps> = ({ items, changeFilter }) => {
const [showClearIcon, setShowClearIcon] = React.useState(false);
return (
<div className="radio-button-list">
{showClearIcon && <div className="clear-icon">clear</div>}
<ul>
{items.map(item => {
/* this is the area what I'm checking the property */
if (item.selected) {
setShowClearIcon(true);
}
return (
<li key={item.id}>
<label htmlFor={item.text} className="radio">
<span className="input">
<input type="radio" onClick={changeFilter} readOnly />
</span>
</label>
</li>
);
})}
</ul>
</div>
);
};
选项 2:
const RadioButtonList: FunctionComponent<RadioButtonListProps> = ({ items, changeFilter }) => {
const [showClearIcon, setShowClearIcon] = React.useState(false);
/* set in useEffect hook */
useEffect(() => {
if(items.some(item => item.selected)) {
setShowClearIcon(true);
}
}, [items]);
return (
<div className="radio-button-list">
{showClearIcon && <div className="clear-icon">clear</div>}
<ul>
{items.map(item => {
return (
<li key={item.id}>
<label htmlFor={item.text} className="radio">
<span className="input">
<input type="radio" onClick={changeFilter} readOnly />
</span>
</label>
</li>
);
})}
</ul>
</div>
);
};
选项 1 在渲染中排队状态更新 return,不要使用它。
作为副作用,使用选项 2 正确地将更新加入队列。在 React 中,渲染函数被认为是一个纯函数。不要无条件地排队状态更新。
关于性能,迭代数组是O(n)
。迭代一个数组两次还是O(n)
.
建议
showClearIcon
“状态”可能不应该是 React 状态,因为它很容易从 items
属性派生。
Identify the Minimal (but complete) Representation of UI State
Let’s go through each one and figure out which one is state. Ask three questions about each piece of data:
- Is it passed in from a parent via props? If so, it probably isn’t state.
- Does it remain unchanged over time? If so, it probably isn’t state.
- Can you compute it based on any other state or props in your component? If so, it isn’t state.
因此,只需在本地计算 showClearIcon
值。
const showClearIcon = items.some(item => item.selected);
这个 可以 与 useMemo
挂钩一起记忆,如果需要的话依赖于 items
。
所以,如果你想纯粹看性能,你可以做的是安装反应开发工具 chrome 扩展,然后在你的测试服务器(例如 localhost:3000)中你可以使用chrome 的 f12 菜单中的分析器选项卡,用于检查哪个操作占用更多内存!
这是您可以用于所有优化问题的东西
如果你的目标是渲染 html 组件,应该使用选项 2 (useEffect),记住依赖数组中只包含必需的依赖项(这是为了避免 re-render 和性能相关的问题)。在你的情况下,选项 2 是正确的,它的性能将由 React 本身调整。
看起来showClearIcon
根本不需要是状态原子,而只是a memoized value依赖于items
。
const showClearIcon = React.useMemo(
() => items.some(item => item.selected),
[items],
);
从技术上讲,您可以在没有 useState
和 useEffect
的情况下完成它,并且无需对数组进行两次迭代,请查看下面的示例(它可能不是必需的,但最好知道这也是可能的):
const RadioButtonList: FunctionComponent<RadioButtonListProps> = ({
items,
changeFilter,
}) => {
const renderItems = () => {
let showClearIcon = false;
let markup = (
<ul>
{items.map((item) => {
if (item.selected) {
showClearIcon = true;
}
return (
<li key={item.id}>
<label htmlFor={item.text} className="radio">
<span className="input">
<input type="radio" onClick={changeFilter} readOnly />
</span>
</label>
</li>
);
})}
</ul>
);
return (
<>
{showClearIcon && <div className="clear-icon">clear</div>}
{markup}
</>
);
};
return <div className="radio-button-list">{renderItems()}</div>;
};
简单地创建了一个生成标记的函数。
选项 2 是更好的方法,但是选项 2 你也可以有更好的编码,如下所示,使代码更好更简单
const RadioButtonList: FunctionComponent<RadioButtonListProps> = ({ items, changeFilter }) => {
// as suggested by AKX
const showClearIcon = React.useMemo(
() => items.some(item => item.selected),
[items],
);
/* set in useEffect hook */
useEffect(() => {
if(items.some(item => item.selected)) {
setShowClearIcon(true);
}
}, [items]);
// for displaying row items
const generateRow = ({id, text}) => {
return (
<li key={item.id}>
<label htmlFor={item.text} className="radio">
<span className="input">
<input type="radio" onClick={changeFilter} readOnly />
</span>
</label>
</li>
);
}
return (
<div className="radio-button-list">
{showClearIcon && <div className="clear-icon">clear</div>}
<ul>
{items.map(item => generateRow(item))}
</ul>
</div>
);
};