- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在使用 Preact(出于所有意图和目的,React)来呈现保存在状态数组中的项目列表。每个项目旁边都有一个删除按钮。我的问题是:单击按钮时,删除了正确的项目(我多次验证了这一点),但是重新呈现的项目缺少 last 项目,而删除的项目仍然存在。我的代码(简化):
import { h, Component } from 'preact';
import Package from './package';
export default class Packages extends Component {
constructor(props) {
super(props);
let packages = [
'a',
'b',
'c',
'd',
'e'
];
this.setState({packages: packages});
}
render () {
let packages = this.state.packages.map((tracking, i) => {
return (
<div className="package" key={i}>
<button onClick={this.removePackage.bind(this, tracking)}>X</button>
<Package tracking={tracking} />
</div>
);
});
return(
<div>
<div className="title">Packages</div>
<div className="packages">{packages}</div>
</div>
);
}
removePackage(tracking) {
this.setState({packages: this.state.packages.filter(e => e !== tracking)});
}
}
我做错了什么?我需要以某种方式主动重新渲染吗?这是 n+1 的情况吗?
澄清:我的问题不在于状态的同步性。在上面的列表中,如果我选择删除“c”,状态将正确更新为 ['a','b','d','e']
,但呈现的组件是['a','b','c','d']
。每次调用 removePackage
时,都会从数组中删除正确的包,显示正确的状态,但会呈现错误的列表。 (我删除了 console.log
语句,所以看起来它们不是我的问题)。
最佳答案
这是一个经典的问题,Preact 的文档完全没有解决这个问题,所以我想亲自为此道歉!如果有人感兴趣,我们一直在寻求帮助来编写更好的文档。
这里发生的事情是您使用数组的索引作为键(在渲染中的 map 中)。这实际上只是模拟 VDOM diff 在默认情况下的工作方式——键总是 0-n
,其中 n
是数组长度,因此删除任何项目只会删除最后一个键列表。
在您的示例中,想象一下(虚拟)DOM 在初始渲染中的外观,然后在删除项目“b”(索引 3)后的外观。下面,让我们假设您的列表只有 3 个项目(['a', 'b', 'c']
):
这是初始渲染产生的结果:
<div>
<div className="title">Packages</div>
<div className="packages">
<div className="package" key={0}>
<button>X</button>
<Package tracking="a" />
</div>
<div className="package" key={1}>
<button>X</button>
<Package tracking="b" />
</div>
<div className="package" key={2}>
<button>X</button>
<Package tracking="c" />
</div>
</div>
</div>
现在,当我们在列表中的第二项上单击“X”时,“b”将传递给 removePackage()
,它将 state.packages
设置为 ['a', 'c']
。这会触发我们的渲染,生成以下(虚拟)DOM:
<div>
<div className="title">Packages</div>
<div className="packages">
<div className="package" key={0}>
<button>X</button>
<Package tracking="a" />
</div>
<div className="package" key={1}>
<button>X</button>
<Package tracking="c" />
</div>
</div>
</div>
因为 VDOM 库只知道你在每次渲染时给它的新结构(不知道如何从旧结构更改为新结构),键所做的基本上是告诉它项目 0
和 1
保持原样 - 我们知道这是不正确的,因为我们希望删除索引 1
处的项目。
记住:key
优先于默认的子 diff 重新排序语义。在此示例中,因为 key
始终只是从 0 开始的数组索引,所以最后一项 (key=2
) 只是被丢弃,因为它是后续项中缺少的一项渲染。
因此,要修复您的示例 - 您应该使用标识 item 而不是其 offset 的内容作为您的 key 。这可以是项目本身(任何值都可以作为键),或 .id
属性(首选,因为它避免分散对象引用,周围可能会阻止 GC):
let packages = this.state.packages.map((tracking, i) => {
return (
// ↙️ a better key fixes it :)
<div className="package" key={tracking}>
<button onClick={this.removePackage.bind(this, tracking)}>X</button>
<Package tracking={tracking} />
</div>
);
});
哇,这比我预想的要冗长得多。
TL,DR:永远不要使用数组索引(迭代索引)作为key
。它充其量只是模仿默认行为(自上而下的子项重新排序),但更多时候它只是将所有差异推到最后一个子项上。
编辑: @tommy recommended这个优秀link to the eslint-plugin-react docs ,这比我在上面所做的更好地解释了它。
关于javascript - Preact 渲染的错误组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42773892/
我目前正在使用 CLI 构建 Preact PWA。 我的理解是,无论我在哪里使用 JSX 定义了组件,我都需要 import { h } from 'preact'在文件的顶部。 我删除了该导入语句
我有一个非常简单的 react 程序,它使用脚本命令和 cdn 导入 react 。 如何在保持相同结构的同时将其转换为预执行? 我试着关注 these说明,但不是很清楚
使用 Preact CLI 是否可以设置应用程序将在根目录之外托管的路径? 例如在 http://mywebsite.com/relativepath/index.html 托管应用程序 最佳答案 您
Preact 标记为 8.5kb,是 Preact 大小的一半。有没有一种方法可以渲染原始 HTML 而无需解析它? 我能想到的一种方法是渲染一个占位符,然后使用innerHTML替换componen
我使用以下堆栈: “依赖”:{ "preact": "^8.2.1", “预兼容”:“^3.17.0”, “preact-redux”:“^2.0.3”, “预路由器”:“^2.5.5”, “redu
如果您在 https://startupguide.vercel.app/ 上访问我的 Preact 应用程序并单击“名称生成器”,您将只看到名称生成器表单(应该如此)。但是如果你去https://s
我只是试图理解Preact信号,所以可能我做错了什么,但我试图允许用户更新一个值,但每当他们这样做时,它就会恢复到缺省值。如果我将其记录下来,它确实会显示更改后的值,但会立即恢复。我是不是遗漏了什么?
I'm just trying to get to grips with Preact Signals so maybe I'm doing something wrong but I'm tr
我正在运行一个带有 preact build 的 preact 项目并按如下方式进行导入:import PresenceToggleAlert from 'async?name=presenceTog
React具有 refs 的概念。 Preact中是否有类似的概念可以在不使用preact-compat的情况下使用? 我希望能够在没有DOM查找的情况下引用Component方法中的元素。 谢谢!
我正在创建一个使用 tsParticles 的 Preact 组件库,但什么也没有出现。 我正在移植 React project但可能有些地方不兼容。 您可以在此处 checkout 组件:https
我对 preact 很陌生,我正在尝试在 preact 中实现 PWA。特别是,此示例应显示人员 ID 列表。 这是index.html页面:
今天我尝试在 webpack 中使用 CSS。它几乎对我有用。 这是目标代码。在浏览器类属性中为空。我尝试了具有相同结果的 className,但 CSS 代码包含在包中。 import css fr
我正在使用 Preact(出于所有意图和目的,React)来呈现保存在状态数组中的项目列表。每个项目旁边都有一个删除按钮。我的问题是:单击按钮时,删除了正确的项目(我多次验证了这一点),但是重新呈现的
Preact CLI声称它支持CSS Modules盒子外面。所以这就是我尝试过的;给定 2 个文件 index.js和 index.module.scss在同一个文件夹中,我尝试了这个: index
简单地导入样式组件会导致浏览器控制台中出现此错误: styled-components.browser.esm.js?face:1670 Uncaught TypeError: (0 , _react
在可编辑的前置元素上,我仅在按下 Enter 键时运行 onKeyDown 脚本,以避免文本中出现不需要的 HTML 元素。 render({}, {content}) { conso
我是 Preact 的新手,我必须为 Preact 中的应用程序编写单元测试用例。我发现 jest 和 enzyme 可以用于相同的用途,但我每次都会遇到错误。谁能推荐一些关于如何在 Preact 上
我对react.js(使用preact)还很陌生,并且遇到了异步路由(preact-async-router)的问题。 我的main.js: import { h, render } from 'pr
我已经使用 preact-cli 创建了一个应用程序,如下所示: preact create 但是没有“索引”页面,我也看不到任何工作脚本或构建文件夹。所以我在徘徊如何访问这些,例如,我可以更改页
我是一名优秀的程序员,十分优秀!