使用 useMemo 而不是 React.memo 语法问题
Using useMemo instead of React.memo syntax issue
我需要做一个使用React Hooks useMemo的演示。我有如下工作代码,可以满足我的要求:
const SpeakerCardDetail = React.memo(
({id,...
我找到了一个 link,表明我可以使用更像这样的语法,但我无法准确地理解它。
据我所知:
const SpeakerDetail = React.useMemo(() => {
({ id,
但显然不是。我确实知道 React.memo 解决了问题,但我确实需要展示 useMemo 的实际效果,我希望我可以使用另一种语法。
React.memo
和 React.useMemo
根本不等价(不要依赖命名相似性)。这是来自 React.memo
doc 的引述:
React.memo
is a higher order component.
因此它是一个可以优化组件呈现的 HOC,因为它呈现具有相同属性的相同输出。
另一方面,React.useMemo
更通用,returns a memoized value:
Pass a “create” function and an array of dependencies. useMemo
will
only recompute the memoized value when one of the dependencies (either a
or b
) has
changed.
const memoizedValue = useMemo(
() => computeExpensiveValue(a, b),
[a, b]
);
虽然它可以被破解以代替 React.memo
使用,但这不是它的目的,它只会增加混乱而不是帮助。 useMemo
是一个钩子,受制于 certain usage rules。
还有这个警告:
In the future, React may choose to “forget” some previously memoized
values and recalculate them on next render, e.g. to free memory for
offscreen components. Write your code so that it still works without
useMemo
— and then add it to optimize performance.
虽然 memo
是一个 HOC 而 useMemo
是一个钩子,你可以使用它们来达到相同的结果。
就上下文而言,HOC 是一种较旧的 React 模式,已与基于 class 的组件和类似的功能组件一起使用多年。您今天仍然可以使用它(没有弃用计划)。
Hooks 是一个相对较新的概念(大约一年),它增强了功能组件,并且在许多情况下显着 simplifies code。这就是为什么许多开发人员正在转向使用钩子。
无论如何,memo
和 useMemo
都有两个参数:函数和 props。如果 none 的道具在随后的重新渲染中发生变化,则该函数不会再次执行,而是 returns 之前的结果。这实际上用纯函数方法取代了 shouldComponentUpdate
回调。
使用 memo
,您的代码将如下所示:
const SpeakerCardDetail = React.memo(
(props) => <div>{props.name}</div>
)
使用 useMemo
,你会写:
const SpeakerCardDetail = (props) => useMemo(() => <div>{props.name}</div>)
请注意,useMemo
用于组件函数内部,而 memo
包装函数。
更传统地说,useMemo
可以写成:
function SpeakerCardDetail(props) {
return useMemo(
() => <div>{props.name}</div>
)
}
现在,上面的代码每次都会重新渲染,使得 useMemo
功能有点无用。为了让它发挥它的魔力,我们需要添加第二个参数。 (memo
即使不指定第二个参数仍然有效,但您可以添加它来自定义它)
第二个参数的格式略有不同。 memo
需要一个比较以前和当前道具的功能,就像 shouldComponentUpdate
对 class 组件所做的那样。
const SpeakerCardDetail = React.memo(
(props) => <div>{props.name}</div>
,
// return true if passing nextProps to render would return the same result as passing prevProps to render, otherwise return false
(prevProps, nextProps) => prevProps.name === nextProps.name
)
另一方面,useMemo
需要一个数组作为第二个参数。每当数组中的值发生变化时,该函数将再次执行。
function SpeakerCardDetail(props) {
return useMemo(
() => <div>{props.name}</div>
,
[props.name]
)
}
真的没有比这更神奇的了。 memo
和 useMemo
都是用来记忆函数的结果,唯一的区别是 memo
是一个 HOC(并且可以用来包装 class 和函数组件) 其中 useMemo
是一个钩子(并且只能在功能组件内部使用)。
总结 React.memo
与 useMemo
/ TLDR:
React.memo
是一个高阶组件(简称HOC),会根据props记忆一个react组件
export function SomeComponent({ num }) {
return <p>{num * 10}</p>
}
export default React.memo(SomeComponent, function areEqual(
prevProps,
nextProps
) {
if (prevProps.num !== nextProps.num) {
return false
}
return true
})
useMemo
是一个反应挂钩,它将记住从您提供的函数返回的值。
export function SomeComponent({ num }) {
const res = useMemo(() => num * 10, [num])
return <p>{res}</p>
}
React.Memo
如果 props 没有改变,使用 React.memo
将导致 React 跳过渲染组件。
示例:
const Child = React.memo(props => {
console.log("rendered");
return <React.Fragment>{props.name}</React.Fragment>;
});
class App extends React.Component {
state = {
value: 1,
name: "Jioke"
};
handleClick = () => {
this.setState({
value: this.state.value + 1
});
};
render() {
return (
<React.Fragment>
<Child name={this.state.name} />
<div>{this.state.value}</div>
<button onClick={this.handleClick}>+</button>
</React.Fragment>
);
}
}
当我们点击按钮时,Child
组件不会重新渲染(rendered
只显示1)
注:道具越多,计算越多,比较(检查是否渲染)增加的比较成本是不值得的对于渲染、协调、DOM 更改和副作用成本方面的“简单”组件。所以慎用与否
使用备忘录
useMemo
将缓存一个值,这样就不需要在每次重新渲染组件时都重新计算它。如果输入未更改,它会保存 return 函数值和 returns。
示例:
import { useState, useMemo } from "react";
import ReactDOM from "react-dom";
const App = () => {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
const calculation = useMemo(() => expensiveCalculation(count), [count]);
const increment = () => {
setCount((c) => c + 1);
};
const addTodo = () => {
setTodos((t) => [...t, "New Todo"]);
};
return (
<div>
<div>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</div>
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
<h2>Expensive Calculation</h2>
{calculation}
</div>
</div>
);
};
const expensiveCalculation = (num) => {
console.log("Calculating...");
for (let i = 0; i < 1000000000; i++) {
num += 1;
}
return num;
};
ReactDOM.render(<App />, document.getElementById('root'));
我们有一个昂贵的功能,运行在每个渲染器上。
更改计数或添加待办事项时,您会注意到执行延迟。
因此,当我们使用 useMemo
时,昂贵的函数只会在其依赖项发生变化时 运行 。
在下面的示例中,昂贵的函数仅在计数更改时才会 运行 而不是在添加待办事项时。
我需要做一个使用React Hooks useMemo的演示。我有如下工作代码,可以满足我的要求:
const SpeakerCardDetail = React.memo(
({id,...
我找到了一个 link,表明我可以使用更像这样的语法,但我无法准确地理解它。
据我所知:
const SpeakerDetail = React.useMemo(() => {
({ id,
但显然不是。我确实知道 React.memo 解决了问题,但我确实需要展示 useMemo 的实际效果,我希望我可以使用另一种语法。
React.memo
和 React.useMemo
根本不等价(不要依赖命名相似性)。这是来自 React.memo
doc 的引述:
React.memo
is a higher order component.
因此它是一个可以优化组件呈现的 HOC,因为它呈现具有相同属性的相同输出。
另一方面,React.useMemo
更通用,returns a memoized value:
Pass a “create” function and an array of dependencies.
useMemo
will only recompute the memoized value when one of the dependencies (eithera
orb
) has changed.
const memoizedValue = useMemo(
() => computeExpensiveValue(a, b),
[a, b]
);
虽然它可以被破解以代替 React.memo
使用,但这不是它的目的,它只会增加混乱而不是帮助。 useMemo
是一个钩子,受制于 certain usage rules。
还有这个警告:
In the future, React may choose to “forget” some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without
useMemo
— and then add it to optimize performance.
虽然 memo
是一个 HOC 而 useMemo
是一个钩子,你可以使用它们来达到相同的结果。
就上下文而言,HOC 是一种较旧的 React 模式,已与基于 class 的组件和类似的功能组件一起使用多年。您今天仍然可以使用它(没有弃用计划)。
Hooks 是一个相对较新的概念(大约一年),它增强了功能组件,并且在许多情况下显着 simplifies code。这就是为什么许多开发人员正在转向使用钩子。
无论如何,memo
和 useMemo
都有两个参数:函数和 props。如果 none 的道具在随后的重新渲染中发生变化,则该函数不会再次执行,而是 returns 之前的结果。这实际上用纯函数方法取代了 shouldComponentUpdate
回调。
使用 memo
,您的代码将如下所示:
const SpeakerCardDetail = React.memo(
(props) => <div>{props.name}</div>
)
使用 useMemo
,你会写:
const SpeakerCardDetail = (props) => useMemo(() => <div>{props.name}</div>)
请注意,useMemo
用于组件函数内部,而 memo
包装函数。
更传统地说,useMemo
可以写成:
function SpeakerCardDetail(props) {
return useMemo(
() => <div>{props.name}</div>
)
}
现在,上面的代码每次都会重新渲染,使得 useMemo
功能有点无用。为了让它发挥它的魔力,我们需要添加第二个参数。 (memo
即使不指定第二个参数仍然有效,但您可以添加它来自定义它)
第二个参数的格式略有不同。 memo
需要一个比较以前和当前道具的功能,就像 shouldComponentUpdate
对 class 组件所做的那样。
const SpeakerCardDetail = React.memo(
(props) => <div>{props.name}</div>
,
// return true if passing nextProps to render would return the same result as passing prevProps to render, otherwise return false
(prevProps, nextProps) => prevProps.name === nextProps.name
)
另一方面,useMemo
需要一个数组作为第二个参数。每当数组中的值发生变化时,该函数将再次执行。
function SpeakerCardDetail(props) {
return useMemo(
() => <div>{props.name}</div>
,
[props.name]
)
}
真的没有比这更神奇的了。 memo
和 useMemo
都是用来记忆函数的结果,唯一的区别是 memo
是一个 HOC(并且可以用来包装 class 和函数组件) 其中 useMemo
是一个钩子(并且只能在功能组件内部使用)。
总结 React.memo
与 useMemo
/ TLDR:
React.memo
是一个高阶组件(简称HOC),会根据props记忆一个react组件
export function SomeComponent({ num }) {
return <p>{num * 10}</p>
}
export default React.memo(SomeComponent, function areEqual(
prevProps,
nextProps
) {
if (prevProps.num !== nextProps.num) {
return false
}
return true
})
useMemo
是一个反应挂钩,它将记住从您提供的函数返回的值。
export function SomeComponent({ num }) {
const res = useMemo(() => num * 10, [num])
return <p>{res}</p>
}
React.Memo
如果 props 没有改变,使用 React.memo
将导致 React 跳过渲染组件。
示例:
const Child = React.memo(props => {
console.log("rendered");
return <React.Fragment>{props.name}</React.Fragment>;
});
class App extends React.Component {
state = {
value: 1,
name: "Jioke"
};
handleClick = () => {
this.setState({
value: this.state.value + 1
});
};
render() {
return (
<React.Fragment>
<Child name={this.state.name} />
<div>{this.state.value}</div>
<button onClick={this.handleClick}>+</button>
</React.Fragment>
);
}
}
当我们点击按钮时,Child
组件不会重新渲染(rendered
只显示1)
注:道具越多,计算越多,比较(检查是否渲染)增加的比较成本是不值得的对于渲染、协调、DOM 更改和副作用成本方面的“简单”组件。所以慎用与否
使用备忘录
useMemo
将缓存一个值,这样就不需要在每次重新渲染组件时都重新计算它。如果输入未更改,它会保存 return 函数值和 returns。
示例:
import { useState, useMemo } from "react";
import ReactDOM from "react-dom";
const App = () => {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
const calculation = useMemo(() => expensiveCalculation(count), [count]);
const increment = () => {
setCount((c) => c + 1);
};
const addTodo = () => {
setTodos((t) => [...t, "New Todo"]);
};
return (
<div>
<div>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</div>
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
<h2>Expensive Calculation</h2>
{calculation}
</div>
</div>
);
};
const expensiveCalculation = (num) => {
console.log("Calculating...");
for (let i = 0; i < 1000000000; i++) {
num += 1;
}
return num;
};
ReactDOM.render(<App />, document.getElementById('root'));
我们有一个昂贵的功能,运行在每个渲染器上。
更改计数或添加待办事项时,您会注意到执行延迟。
因此,当我们使用 useMemo
时,昂贵的函数只会在其依赖项发生变化时 运行 。
在下面的示例中,昂贵的函数仅在计数更改时才会 运行 而不是在添加待办事项时。