这是我当时的代码,我使用了index作为key,当时的场景是这样的:
1.第一次我选择了张晓宇,它这时位于列表第三
2.我搜索"张"这个字,并向后端发送请求重新获取数据渲染列表
3.此时张晓宇位于第一位,蓝的勾选的位置也在第一位,但是可以观察input框此时第一位的名字(lable)是重新获取数据后排位第三的张*鹏,而并非张晓宇。
解决方式像下面这串代码一样绑定唯一值就可以了,造成这样的原因我猜测是diff算法的原因.
- :key=“iabilityManItem.id”
<el-form-item label="责任人">
<el-select v-model="form.liabilityMan" placeholder="请选择" multiple filterable remote :remote-method="findUserByStatus" value-key="name" :disabled="!isEdit">
<el-option
v-for="(liabilityManItem,liabilityManIndex) in liabilityManList"
:key="'liabilityManList'+liabilityManIndex"
:label="liabilityManItem.name"
:value="liabilityManItem.value"
/>
</el-select>
</el-form-item>
DOM的diffing算法
- 我们操作数据时不是直接将数据挂在DOM上,而是现在生成的虚拟DOM上进行比较,例如下图对比03是新加的,之前没有的,那么就将03映射成新的真实DOM
1.1如何证明?
- 这里时间是实时改变的,但是在input框输入的值并没有被刷掉,哪怕在h1标签内再套标签也不会被刷掉,因为是深层对比,
<script type="text/babel">
class Demo extends React.Component {
state = { time: new Date() }
componentDidMount() {
setInterval(() => {
this.setState({ time: new Date() })
}, 1000)
}
render() {
return (
<div>
<input type="text" />
<h1>{this.state.time.toTimeString()}</h1>
</div>
)
}
}
ReactDOM.render(<Demo />, document.getElementById('text'))
</script>
1.2key
1.2.1react/vue中的key有什么作用?(key的内部原理是什么?)
- 简单的说:Key是虚拟DOM对象的标识,在更新显示时Key起着极其重要的作用.
- 详细的说:当状态中的数据发生变化时,react会根据
新数据
生成新的虚拟DOM
,随后React进行新虚拟DOM
与旧虚拟DOM
的diff比较,比较规则如下:
a.旧数据DOM中找到了与新虚拟DOM相同的Key:
1.若虚拟DOM中内容没变,直接使用之前的真实DOM
2.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
b.旧虚拟DOM中未找到与新虚拟DOM相同的Key
- 根据数据创建新的真实DOM,随后渲染到页面
1.2.2 为什么遍历列表时,key最好不要用index?
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新==>界面效果没问题,但效率低
- 如果结构中还包含输入类的DOM,会产生错误DOM更新==>界面有问题
- 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的
<script type="text/babel">
/**
* 慢动作回放
* 初始数据:
* { name: '兰博基尼', num: 1000, id: 1 }
* { name: '拖拉机', num: 2000, id: 2 }
*
* 初始虚拟DOM:
* <li key=0>兰博基尼---1000</li>
* <li key=1>拖拉机---2000</li>
*
* 更新后数据
* { name: '玛莎拉蒂', num: 3000, id: 3 }
* { name: '兰博基尼', num: 1000, id: 1 }
* { name: '拖拉机', num: 2000, id: 2 }
*
* 更新数据后的虚拟DOM
* <li key=0>玛莎拉蒂---3000</li>
* <li key=1>兰博基尼---1000</li>
* <li key=2>拖拉机---2000</li>
*/
class Demo extends React.Component {
state = { car: [{ name: '兰博基尼', num: 1000, id: 1 }, { name: '拖拉机', num: 2000, id: 2 }] }
add = (() => {
const car = { name: "玛莎拉蒂", num: 3000, id: this.state.car.length + 1 }
this.setState({ car: [car, ...this.state.car] })
})
render() {
return (
<div>
<button onClick={this.add}>添加</button>
<ul>
{this.state.car.map((carItem, carIndex) => {
return <li key={carIndex}>{carItem.name}---{carItem.num}</li>
})
}
</ul>
</div>
)
}
}
ReactDOM.render(<Demo />, document.getElementById('text'))
</script>
- 本来只需要操作一条数据,现在全部都需要重新挂真实DOM,数据一多性能就差
1.2.3使用index做索引值导致数据错乱
- 1.input框写上内容2.点击添加时input内容没有改变
虚拟dom没有value值,只有放在真实dom上才有
<script type="text/babel">
/**
* index慢动作回放
* 初始数据:
* { name: '兰博基尼', num: 1000, id: 1 }
* { name: '拖拉机', num: 2000, id: 2 }
*
* 初始虚拟DOM:
* <li key=0>兰博基尼---1000<input /></li>
* <li key=1>拖拉机---2000<input /></li>
*
* 更新后数据
* { name: '玛莎拉蒂', num: 3000, id: 3 }
* { name: '兰博基尼', num: 1000, id: 1 }
* { name: '拖拉机', num: 2000, id: 2 }
*
* 更新数据后的虚拟DOM
* <li key=0>玛莎拉蒂---3000<input /></li>
* <li key=1>兰博基尼---1000<input /></li>
* <li key=2>拖拉机---2000<input /></li>
*/
/**
* id慢动作回放
* 初始数据:
* { name: '兰博基尼', num: 1000, id: 1 }
* { name: '拖拉机', num: 2000, id: 2 }
*
* 初始虚拟DOM:
* <li key=1>兰博基尼---1000<input /></li>
* <li key=2>拖拉机---2000<input /></li>
*
* 更新后数据
* { name: '玛莎拉蒂', num: 3000, id: 3 }
* { name: '兰博基尼', num: 1000, id: 1 }
* { name: '拖拉机', num: 2000, id: 2 }
*
* 更新数据后的虚拟DOM
* <li key=3>玛莎拉蒂---3000<input /></li>
* <li key=1>兰博基尼---1000<input /></li>
* <li key=2>拖拉机---2000<input /></li>
*/
class Demo extends React.Component {
state = { car: [{ name: '兰博基尼', num: 1000, id: 1 }, { name: '拖拉机', num: 2000, id: 2 }] }
add = (() => {
const car = { name: "玛莎拉蒂", num: 3000, id: this.state.car.length + 1 }
this.setState({ car: [car, ...this.state.car] })
})
render() {
return (
<div>
<button onClick={this.add}>添加</button>
<h1>使用index</h1>
<ul>
{this.state.car.map((carItem, index) => {
return <li key={index}>{carItem.name}---{carItem.num}<input /></li>
})
}
</ul>
<h1>使用id</h1>
<ul>
{this.state.car.map((carItem) => {
return <li key={carItem.id}>{carItem.name}---{carItem.num}<input /></li>
})
}
</ul>
</div>
)
}
}
ReactDOM.render(<Demo />, document.getElementById('text'))
</script>
1.2.4使用唯一值做key
<script type="text/babel">
/**
* 慢动作回放
* 初始数据:
* { name: '兰博基尼', num: 1000, id: 1 }
* { name: '拖拉机', num: 2000, id: 2 }
*
* 初始虚拟DOM:
* <li key=1>兰博基尼---1000</li>
* <li key=2>拖拉机---2000</li>
*
* 更新后数据
* { name: '玛莎拉蒂', num: 3000, id: 3 }
* { name: '兰博基尼', num: 1000, id: 1 }
* { name: '拖拉机', num: 2000, id: 2 }
*
* 更新数据后的虚拟DOM
* <li key=3>玛莎拉蒂---3000</li>
* <li key=1>兰博基尼---1000</li>
* <li key=2>拖拉机---2000</li>
*/
class Demo extends React.Component {
state = { car: [{ name: '兰博基尼', num: 1000, id: 1 }, { name: '拖拉机', num: 2000, id: 2 }] }
add = (() => {
const car = { name: "玛莎拉蒂", num: 3000, id: this.state.car.length + 1 }
this.setState({ car: [car, ...this.state.car] })
})
render() {
return (
<div>
<button onClick={this.add}>添加</button>
<ul>
{this.state.car.map((carItem) => {
return <li key={carItem.id}>{carItem.name}---{carItem.num}</li>
})
}
</ul>
</div>
)
}
}
ReactDOM.render(<Demo />, document.getElementById('text'))
</script>