为什么 React 需要 Immutable?

前端桃园

共 4477字,需浏览 9分钟

 ·

2021-03-31 13:42

作者:水墨寒

掘金ID:https://juejin.cn/user/3051900006317549



对⼀个问题的研究,尝试⽤⻩⾦圈法则来分析。

  • Why 为什么 React 需要 immutable
  • How 如何在使⽤ React 使⽤ immutable
  • What 带来的收益和结果

为什么要在React 使⽤ immutable


⼀句话概况: React 使⽤了 shallowCompare 来决定是否应该重新渲染⼀个组件。

要理解 shallowCompare,我们⾸先需要知道 JavaScript 是如何处理对象引⽤的。让我们来看 ⼀个例⼦:

const people = [{ name"mary"age20 }, { name"john"age30 }];
const john = people[1];
const jonhClone = { name"john"age30 };
console.log(john === people[1]) // true
console.log(john === jonhClone) // false
people[1].age = 31;
console.log(john) // { name: "john", age: 31 }
console.log(jonhClone) // { name: "john", age: 30 }

johnClonenameagejohn 相同,但他们不是同⼀个⼈。当我们声明 john = people[1], 我们没有拷⻉ people[1]nameagejohn ,两个变量都指向同⼀个对象作为引⽤。



ShallowCompare

现在我们来看⼀个 shallowCompare的例⼦:

let oldProps = null;
function shallowCompare (props){
 if(props !== oldProps) console.log(props);
 oldProps = props;
}
const mary = { name"mary"age20 };
const john = { name"john"age30 };
shallowCompare(mary) // prints -> { name: "mary", age: 20 }
shallowCompare(john) // prints -> { name: "john", age: 30 }
john.age = 31;
shallowCompare(john) // will not print!

如果我们想打印 john 的更新,我们需要浅拷⻉它。这样⼀来,shallowCompare 就会知道道具发⽣了变化。

let oldProps = null;
function shallowCompare (props){
 if(props !== oldProps) console.log(props);
}
const john = { name"john"age30 };
shallowCompare(john) // prints -> { name: "john", age: 30 }
const johnClone = {...john};
johnClone.age=31;
shallowCompare(johnClone) // prints -> { name: "john", age: 31 }

React 中的例⼦

React 使⽤同样的原则来避免不必要的组件重渲染。

class People extends Component {
 constructor(props) {
   super(props);
   this.state = {
    people:[{ name"mary"age25 }, { name"john"age30 }]
   };
 }
 updateJohnAge = ()=>{
   const people = [...this.state.people];
   people[1].age=31;
   this.setState({people});
   //This will not work.
   //People is a new array, but john is the same object
 }
 render() {
   return (
     <div>
       <Person person={this.state.people[1]}></Person>
       <button onClick={this.updateJohnAge}>Set john age to 31</button>
     </div>

   );
 }
}
class Person extends Component {
 render() {
   const { person } = this.props;
   return (
     <div>
       <p>name: {person.name}</p>
       <p>age: {person.age}</p>
     </div>

    );
  }
}

如果我们点击按钮,组件将不会呈现 john 的更新,因为 people[1] 是上次的同⼀个引⽤。为此,没有改变 john 。我们需要在之前克隆 john ,然后更新数组。

updateJohnAge = () =>{
 const people = [...this.state.people];
 const johnClone = {...people[1]};
 johnClone.age = 31;
 people[1] = johnClone;
 this.setState({people});
 //This will work.
}

要知道,我们并没有拷⻉ people[0] (mary)Immutable 并不意味着我们要详尽地克隆所有对象的 ramifications。这将不会很有效率。我们只需要通过我们改变的路径来创建新的引⽤。




推荐阅读




我的公众号能带来什么价值?(文末有送书规则,一定要看)

每个前端工程师都应该了解的图片知识(长文建议收藏)

为什么现在面试总是面试造火箭?

浏览 10
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报