this.state = {
id : 1,
value : "test"
render(
const { id, value } = this.state;
return(
id: { id }, value: { value }
</div>
这里的 const { id, value } = this.state
其实就是一次浅复制, 我们通常用于在渲染的时候提供一些变化的值,而不需要我们在render中对某个变量进行其他操作。所以在明确只是浅复制的情况下,尽量使用const定义变量,因为const定义的变量不能赋值或更改,这样就避免了后面不小心改变了该变量而引起的问题了。浅复制的好处就是可以有效的节约内存地址,避免不必要的内存浪费。
回到代码一,如果不希望只对 obj 复制一个内存地址,那么就要给 newObj 分配一个新的内存地址,然后进行赋值。
let obj = {a: 1};
let newObj = {};
newObj = obj;
newObj.a = 2;
console.log(obj.a);
这里可以看作一次深复制,我们获得了一个新的对象以及新的内存地址,之后对newObj的操作不会影响到obj,可以大胆放心的操作。
深复制(deepCopy)
代码三的例子是一次显而易见的深复制,先分配一个内存地址然后再赋值。除了这种方法,我们还可以使用es6中的Object.assign()方法实现深复制。
let obj = {a: 1, b:{ c: 2}};
let newObj = Object.assign({},obj);
newObj.a = 2;
newObj.b.c = 3;
console.log(obj.a);
console.log(obj.b.c)
可以看到对 newObj.a 赋值后obj并没有改变,然而对 newObj.b.c 赋值之后, obj的值却改变了。这是因为 Object.assign() 方法只能深复制第一层的变量,所以第二层其实是一次浅复制。我们需要对obj.b也用一次Object.assign()才能完成一次完整的深复制。如果obj里面有很多层,就要循环嵌套使用Object.assign()方法很多次。代码三中的方法也只能深复制一层。
在ES7中可以利用 … 对对象解构并且对对象中需要深复制的变量进行拷贝。
let obj = {a:1,b:2};
let newObj = {...obj,a:2};
newObj.b = 3;
console.log(obj);
console.log(newObj);
在reducer中经常会用到这种方式来更新我们的state,从而达到重新渲染的目的。
const initialState = {
count: 1,
value: { name : "Michael" }
function reducer(state = initialState, action){
switch(action.type){
case ADD_COUNT:
return { ...state, count: state.count + 1 };
case CHANGE_NAME:
return { ...state, value : { name : "Lyle" } }
default:
return state;
state & props
改变state需要用到 setState() 方法,setState() 方法属于深复制,最常用的写法就是
this.state = {
value: { a: 1 }
const { value } = this.state;
value.a = 2;
console.log(this.state.value.a);
this.setState({ value });
这里 value.a = 2 虽然已经改变了state中value的值,但由于是浅复制,新旧value指向的是同一块内存地址,组件更新时(state,props改变)默认只比较新旧对象的内存地址是否一致,如果一致则不更新。同理,如果在reducer中,直接对当前的state进行修改并返回props,相应的调用该props的组件不会更新渲染。
const initialState = {
count: 1
function reducer(state = initialState, action){
switch(action.type){
case ADD_COUNT:
state.count += 1;
return { ...state };
default:
return state;
基于组件更新的原理,即比较新旧state或props是否指向同一块内存地址,如果是则不更新,如果不是则更新。也就是说就算是两个对象的值相等但不指向同一地址,dom也会重新渲染。这并不是我们想要看到的,我们需要的是当props的值改变的时候dom重新渲染。我们可以在shouldComponentUpdate()方法里面定义dom是否更新的条件,如 if ( props === nextProps ) return true。
完全的深复制
之前谈到的深复制基本是只能复制一层变量,或者必须嵌套着复制多层变量。如果想要更方便的完全复制一个对象,我们可以使用以下方法。
1.使用JSON.stringify()和parse()方法,如:
const newValue = JSON.parse(JSON.stringify(value));
2.lodash —— .clone(obj, true) / .cloneDeep(obj)
1.在reducer中更新state的时候尽量确保每次都返回一个新(深复制)的对象;
2.在常用的组件中使用shouldComponentUpdate()方法提高渲染效率;
React中的浅复制与深复制 学习前端不到一年,在编写react框架下的代码时,经常会遇到明明已经改变了props页面却没有重新渲染的问题。于是为自己整理了一下关于react中的浅复制与深复制的区别以及实现方式,希望对刚刚入门前端的童鞋们也有所帮助。
受控组件与非受控组件在官网与国内网上的资料都不多,有些人觉得它可有可不有,也不在意。这恰恰显示React的威力,满足不同规模大小的工程需求。譬如你只是做ListView这样简单的数据显示,将数据拍出来,那么for循坏与 {} 就足够了,但后台系统存在大量报表,不同的表单联动,缺了受控组件真的不行。
受控组件与非受控组件是React处理表单的入口。从React的思路来讲,作者肯定让数据控制一切,或者简单的理解为,页面的生成与更新得忠实地执行JSX的指令。
但是表单元素有其特殊之处,用户可以通过键盘输入与鼠标选择,改变界面的显示。界面的改变也意味着有一些数据被改动,比较明显的是input的 val
在react hook中使用到深拷贝( let tempBlockData = […blockData]; ),是将state值重新赋值,再进行操作。之所以使用到深拷贝,是为了解决useState定义的state值无法直接更新和操作,所以,为了直接操作state的blockData,先进行深拷贝,然后再用对应的setState进行更新。
什么是深拷贝,什么是浅拷贝?
假设将A复制给B,即B=A,如果B的改变,A也会改变,就是浅拷贝,如果A没有改变,就是深拷贝,(其实深拷贝只针对较为复杂的object类型数据
1. 性能意义:保持state不变这个约束引导我们使用局部更新对象的方法,这样会可以非常有效地提高react或其他显示框架的渲染效率。我们先来看看为了保持数据不变性,要怎么对state做更新,以我们的苹果篮子state为例:
例子:通知开始摘苹果:apple/BEGIN_PICK_APPLE
为了保证每个版本的state不变性,我们有两种实现方式:“深复制”,“浅复制”。我们来看两种模
1.state值不可直接修改,且在state操作过程中,也需要确认state原来的值没被修改。
const [arr,setArr] = useState([1,2,3])
const [obj,setObj] = useState({a:1,b:2})
1.需求:向arr数组加入一个数字4元素,向对象obj加一个属性c:3
//错误写法:
arr.push(4)
obj.c = 3
// 正确写法
setArr([...arr,4])
setObj({...obj,c:3})
2.需求 操作过程
今天遇到一个问题,我更新了数组里面的数据,但是页面并没有检测到页面的改变。而导致这个原因是,就是浅拷贝和深拷贝的问题。
当我们针对数组对象嵌套比较深时,采用浅拷贝的方式就会出现上述情况。一般也是针对数据结构毕竟深时,采用深拷贝
下面举个针对多层嵌套数组对象的栗子
const arr = [
[{a:'1'},{b:'2'},{c:'3'}],
[{a:'1'},{b:'2'},{c:'3'}],
[{a:'1'},{b:'2'},{c:'3'}]
发布时间:2017-03-09 11:13:46 作者:杨川宝
这篇文章主要为大家详细介绍了react性能优化达到最大化的方法,一步一步优化react性能的过程,告诉大家使用immutable.js的必要性,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
一行代码胜过千言万语。这篇文章呢,主要讲述我一步一步优化rea...
props
1、在子组件中,通过 props 来定义接收时候的名字 props: ['list']
2、我们在父组件中传递值的时候,要在使用子组件的时候,通过 属性名 = 值 的方式来传递,其中 属性名必须是在子组件中 props 定义好的,值也要注意,如果值是来源于模型中话,必须进行绑定
$emit
1、在子组件中,通过触发自定义事件 this.$emit('自定义事件名称',值),进行传值,第一个参数必须写,第二个参数是可
function copy(e) {
let transfer = document.createElement('input');
document.body.appendChild(transfer);
transfer.value = t