javascript - 在 React 中,当用于渲染的数组发生变化时,如何避免不必要的重新渲染?
问题描述
在类似的问题中,解决方案是在遍历数组以呈现组件时使用唯一值而不是地图索引作为“键”道具。但是,它对我不起作用,因为在我从数组中删除一个元素后,remaning 组件仍然会重新呈现。我在这里想念什么?
这是我的尝试,但没有按预期工作:</p>
应用程序.js
import { useState } from "react";
import Column from "./Column.js";
export default function App() {
const data = [
{
name: "lebron",
age: 36,
team: "lakers"
},
{
name: "chris",
age: 36,
team: "suns"
},
{
name: "james",
age: 32,
team: "nets"
}
];
const [players, setPlayers] = useState(data);
const handleClick = () => {
return function () {
const p = [...players];
p.splice(0, 1);
setPlayers(p);
};
};
return (
<>
<table>
<tr>
<td>name</td>
<td>age</td>
<td>team</td>
</tr>
{players.map((p) => (
<Column key={p.name} player={p} onClick={handleClick(p.name)} />
))}
</table>
<button onClick={handleClick()}>Delete</button>
</>
);
}
列.js:
import React from "react";
export default function Column({ player, onClick }) {
console.log(player.name, "update", Date());
return (
<tr>
<td>{player.name}</td>
<td>{player.age}</td>
<td>{player.team}</td>
</tr>
);
}
解决方案
这是默认的 React 行为。
孩子更新,因为发生了父亲状态的更新。
如果你只想在 props 改变时重新渲染子组件,你需要用React.memo HOC 包装你的子组件。
简而言之,使用React.memo
React 第一次渲染您的组件,记住结果,然后重用上次渲染的结果(跳过不必要的重新渲染)。
React.memo 仅检查 prop 更改。如果你封装的函数组件在其实现中React.memo
有一个useState
,useReducer
或useContext
Hook ,它仍然会在状态或上下文改变时重新渲染。
在你的情况下:
列.js 文件
import { memo } from "react";
function Column({ player, onClick }) {
console.log(`Render player ${player.name}`);
return (
<tr>
<td>{player.name}</td>
<td>{player.age}</td>
<td>{player.team}</td>
<button onClick={() => onClick(player)}>Delete</button>
</tr>
);
}
export default memo(Column);
应用程序.js 文件
import { useState, useCallback } from "react";
import Column from "./Column";
const data = [
{
name: "lebron",
age: 36,
team: "lakers"
},
{
name: "chris",
age: 36,
team: "suns"
},
{
name: "james",
age: 32,
team: "nets"
}
];
export default function App() {
const [players, setPlayers] = useState(data);
const handleClick = useCallback((deleted) => {
setPlayers((prevState) =>
prevState.filter((player) => player.name !== deleted.name)
);
}, []);
return (
<>
<table>
<tr>
<td>name</td>
<td>age</td>
<td>team</td>
</tr>
{players.map((p) => (
<Column key={p.name} player={p} onClick={handleClick} />
))}
</table>
{/* This button makes no sense */}
<button onClick={() => handleClick(players[0])}>Delete</button>
</>
);
}
我对您的代码进行了一些更改:
handleClick
功能不对。当您使用时,splice
您正在修改玩家数组,并且在 React 状态下只能使用调度函数(setPlayers )进行修改。在您的情况下,您应该使用filter方法,因为它返回一个新数组。const handleClick = (deleted) => { setPlayers((prevState) => prevState.filter((player) => player.name !== deleted.name) ); };
Column
用 React.memo HOC包装你的组件。
export default React.memo(Column);
用useCallback包装你的
handleClick
函数。这是因为你使用 React.memo 需要记忆你的函数。const handleClick = useCallback((deleted) => { setPlayers((prevState) => prevState.filter((player) => player.name !== deleted.name) ); }, []);
推荐阅读
- app-inventor - App Inventor 2 和 Raspberry pi 之间通过 USB 进行通信?
- java - 如何使用 jfrog cli 上传到 Artifactory 使用 group artifactid 版本分类器和打包
- r - R中的简单T变换出错了
- reactjs - 尝试在 React.js 应用程序中使用 http-proxy-middleware 访问外部 API
- video-streaming - Gstreamer 管道的多个实例导致视频损坏?
- sql - 在 SQL Server 中,如何从另一个表更新表?
- kotlin - 正确实施计划价值
- odoo - 如何在树视图上默认隐藏或删除复选框列?
- javascript - 我试图将数字放入数组而不放入重复项
- jquery - 在规则中使用 php 会话值进行自定义 jquery 验证