美文网首页
JavaScript不可变数据

JavaScript不可变数据

作者: JakeBless | 来源:发表于2021-11-05 10:18 被阅读0次

    什么是数据不可变

    数据一旦创建,就不可更改

    immutable对象是不可直接赋值的对象,它可以有效的避免错误赋值的问题

    什么是可变数据? 比如javascript的绝大多数数据(let var命名的变量,对象等)其实就是可变数据

    // 比如说这种情况

    var a  = {
      x: 1
    }
    
    var b = a
    b.x = 2
    console.log(a.x)
    

    // 再来举一个react的例子

    https://codesandbox.io/s/dreamy-panka-de7u9?file=/src/App.js:153-171

    // 那常规得解决方式无非是深拷贝
    var b = clouedeep(a)
    b.x = 2

    但是深拷贝在频繁的操作当中,比较消耗内存,性能很差

    那如果尝试使用immutable呢?

    immutable库

    immutable.js

    https://www.npmjs.com/package/immutable

    immutable介绍 对immutable对象的任何修改或删除添加都会返回一个新的immutable对象。
    概念: Map List

    import { Map } from 'immutable';
    let a = Map({
      select: 'users',
      filter: Map({ name: 'Cam' })
    })
    let b = a.set('select', 'people');
    
    a === b; // false
    a.get('filter') === b.get('filter'); // true
    

    immer.js

    https://www.npmjs.com/package/immer

    immer当中没有单独的数据类型

    import { produce } from 'immer'
    var a  = {
       x: 1
    }
    
    var b = immer.produce()
    b = immer.produce((draft) => {
        draft.x = 2
    })
    // b.x = 2
    
    console.log(b)  答案是什么?
    

    有人会说用...展开语法不就解决了react的这个setState的问题吗?

    let [t, setT] = useState({ a: 1 });
    setT((state) => {
        ...t,
        t.a: 2
    });
     
    // 但下面这种情况呢? 
    let [adress, setAdress] = useState({
      phone: 123,
      city: {
        code: '1234',
        area: 'beijing'
      }
    })
    
    setAdress({
      ...address,
      city: {
        ...address.city,
        area: "Chengd"
      }
    })
    

    但是如果使用immer解决上述React遇到的问题

       let [t, setT] = useState({ a: 1 });
       setT(
          produce(t, (t) => {
             t.a = 2;
          })
       );
       
       // 第二个复杂数据的例子
       setAdress(prevState => produce(prevState, (draftState) = > {
        draftState.address.city.area = 'JingAn'
        draftState.address.postcode += 10
       })
       
    
       // 进一步简写
        setAdress(
          produce((draftState) => {
            draftState.address.city.area = 'JingAn'
            draftState.address.postcode += 10
          })
       )
    

    不可变数据的应用范围

    • react setState

      import { produce } from 'immer'
      let [t, setT] = useState({ a: 1 });
          setT(
              produce(t, (t) => {
                t.a = 2;
              }
          )
      );
      

      if use use-immer

      import useImmer from 'use-immer'
      const [immer, setImmer] = useImmer({
        name: "Ming",
        sex: 'femal',
        age: 18
      })
      
      setImmmer(draft => {
        draf.age ++
      })
      
    • react redux

    下面介绍一下redux的immer应用(可以参考redux的例子里的src/reducers/index.js尝试一下)
    https://github.com/reactjs/redux/tree/master/examples/counter

    // 不使用 immer
    export default (state = { count: 0 }, action) => {
      switch (action.type) {
        case "INCREMENT":
          return {
            count: state.count + 1
          };
        case "DECREMENT":
          return {
            count: state.count - 1
          };
        default:
          return state;
      }
    };
    
    // 使用 immer 后
    export default (state = { count: 0 }, action) =>
      produce(state, (draftstate) => {
        if (action.type == "INCREMENT") {
          draftstate.count += 1;
        } else if (action.type == "DECREMENT") {
          draftstate.count -= 1;
        }
      });
    
    
    • 复制粘贴 前进后退 时间穿梭

      var a = {x: 1}
      var history = []
      history.push(a)
      history.push(produce(a => { a.x = 2 })
      

    相关文章

      网友评论

          本文标题:JavaScript不可变数据

          本文链接:https://www.haomeiwen.com/subject/ifzkgltx.html