Reactjs React自定义挂钩和useMemo挂钩
我有两个“昂贵”的函数,我想在我的react应用程序中记住它们,因为它们需要很长时间才能呈现。昂贵的函数用于数组映射。我希望记住数组映射的每个结果,这样,如果数组中的一个元素发生了更改,则只会重新计算该元素昂贵的函数。(并且独立地记忆昂贵的函数,因为有时只需要重新计算一个函数。)我正在努力记忆和传递当前数组值 以下是正在运行的演示,没有备忘录:Reactjs React自定义挂钩和useMemo挂钩,reactjs,react-hooks,react-usememo,Reactjs,React Hooks,React Usememo,我有两个“昂贵”的函数,我想在我的react应用程序中记住它们,因为它们需要很长时间才能呈现。昂贵的函数用于数组映射。我希望记住数组映射的每个结果,这样,如果数组中的一个元素发生了更改,则只会重新计算该元素昂贵的函数。(并且独立地记忆昂贵的函数,因为有时只需要重新计算一个函数。)我正在努力记忆和传递当前数组值 以下是正在运行的演示,没有备忘录: import React, { useMemo, useState } from "react"; const input = [
import React, { useMemo, useState } from "react";
const input = ["apple", "banana", "cherry", "durian", "elderberry", "apple"];
export default function App() {
const output = input.map((msg, key) => createItem(msg, key));
return <div className="App">{output}</div>;
}
const createItem = (message, key) => { // expensive function 1
console.log("in createItem:", key, message);
return (
<div key={key}>
<strong>{"Message " + (1 + key)}: </strong>
{message} =>{" "}
<span
id={"preview-" + key}
dangerouslySetInnerHTML={{ __html: msgSub(message) }}
/>
</div>
);
};
const msgSub = message => { // expensive function 2
const messageSub = message.replace(/[a]/g, "A").replace(/[e]/g, "E");
console.log("in msgSub:", message, messageSub);
return messageSub;
};
import React,{usemo,useState}来自“React”;
常量输入=[“苹果”、“香蕉”、“樱桃”、“榴莲”、“接骨木”、“苹果”];
导出默认函数App(){
const output=input.map((消息,键)=>createItem(消息,键));
返回{output};
}
const createItem=(消息,键)=>{///函数1
log(“在createItem:”,键,消息中);
返回(
{“消息”+(1+键)}:
{message}=>{”“}
);
};
const msgSub=message=>{///函数2
const messageSub=message.replace(/[a]/g,“a”).replace(/[e]/g,“e”);
log(“在msgSub:,message,messageSub中”);
返回messageSub;
};
(我没有让它在SO的编辑器上运行,所以请查看并运行它。)
这里是使用自定义钩子和useMemo钩子
任何指导都将不胜感激
以及演示如何在SO的编辑器中对工作做出反应的额外点数 使项目成为纯组件:
const id=((id)=>()=>id++)(1)//iLife创建id
//纯组分
const Item=React.memo(函数项({increase,Item}){
log('rendering id:',item.id);
返回(
增加(item.id)}>
{item.count}
);
});
常量应用=()=>{
const[items,setItems]=React.useState([]);
//使用回调,仅在安装应用程序时增加
常量增加=React.useCallback(
(id)=>
设置项目((项目)=>
//使用状态设置器回调
//useCallback没有依赖项,也没有过时
//闭包
items.map((item)=>
item.id==id
?{…项,计数:项.计数+1}
:项目
)
),
[]//没有依赖项
);
返回(
设置项目((项目)=>[
{id:id(),计数:0},
…项目,
])
}
>
添加计数器
{items.map((item)=>(
))}
);
};
ReactDOM.render(,document.getElementById('root'))代码>
我的第一步是更改createItem
,使该项成为其唯一的功能组件。这意味着我可以记忆
组件,这样它只有在道具更改时才会呈现,重要的是消息和键/索引(正如您之前呈现的值)
这方面的工作示例
const Item=React.memo({message,index})=>{
日志(“呈现:”,索引,消息);
const calculatedMessage=msgSub(消息);
返回(
{“消息”+(1+索引)}:
{message}=>{”“}
);
});
const msgSub=消息=>{
//昂贵的功能2
const messageSub=message.replace(/[a]/g,“a”).replace(/[e]/g,“e”);
log(“在msgSub:,message,messageSub中”);
返回messageSub;
};
您可以看到,在初始渲染时,它会渲染所有项目及其消息
,尤其是apple
两次
如果两个组件彼此独立渲染,并且恰好使用相同的道具,则将渲染这两个组件。React.memo不保存组件渲染
它必须呈现项目组件两次
,一次用于索引0处的apple
,另一次用于索引5处的apple
您会注意到我在应用程序中放置了一个按钮,单击该按钮将更改数组的内容 稍微更改一下原始数组,我将
carrot
放在原始数组的索引4处,并在更新时将其移动到新数组的索引2处
const [stringArray, setStringArray] = React.useState([
"apple",
"banana",
"cherry",
"durian",
"carrot",
"apple" // duplicate Apple
]);
const changeArray = () =>
setStringArray([
"apple",
"banana",
"carrot", // durian removed, carrot moved from index 4 to index 2
"dates", // new item
"elderberry", // new item
"apple"
]);
如果您查看控制台,您将看到在第一次渲染时在msgSub:carrot carrot中看到,但是当我们更新数组时,会再次调用msgSub:carrot carrot
中的。这是因为
上的键被强制重新启动。这是正确的,因为我们的键是基于索引的,胡萝卜改变了位置。然而,您说过msgSub
是一个昂贵的函数
地方回忆录
我注意到在你的阵列中有两次apple
常量输入=[“苹果”、“香蕉”、“樱桃”、“榴莲”、“接骨木”、“苹果”]
我觉得您希望将计算结果记忆起来,这样,如果以前计算过apple
,就不会再次计算apple
我们可以将计算出的值存储在我们自己的记忆状态中,这样我们就可以查找消息值,看看以前是否计算过
const[localmemorization,setlocalmemorization]=useState({});
我们希望确保在stringArray
更改时更新此LocalMemorization
React.useffect(()=>{
SetLocalMemorization(prevState=>
stringArray.reduce((存储,值)=>{
常量计算值=
prevState[值]??存储[值]??msgSub(值);
返回存储区[value]?存储区:{…存储区[value]:calculateValue};
})
);
},[stringArray]);
此行const calculateValue=prevState[value]??存储[值]??msgSub(值)代码>
- 检查previous状态以查看它是否具有previous值(对于carrot将第一个数组移动到第二个数组的情况)
- 检查当前存储以查看其是否具有值(对于第二个存储)
const output = stringArray.map((msg, key) => {
const expensiveMessage = localMemoization[msg];
return (
<Item
key={key}
message={msg}
calculatedValue={expensiveMessage}
index={key}
/>
);
});