深拷贝、浅拷贝 react的“不可变值”

知识获取源--晨哥(现实中的人 嘿嘿)

react中如果你想让一个值始终不变 或者说其他操作不影响该值 它只是作用初始化的时候

使用了浅拷贝--改变了初始值

会改变初始值(selectList1) 因为使用浅拷贝都指向同一个地址

  const selectList1 = { title: '大大', value: '1' };
    const [list1, setList1] = useState(selectList1);// 列表
    list1.title = 'xiaoxiao';
    list1.value = '2';
    console.log('list1', list1, 'selectList1', selectList1);

使用浅拷贝结合react--实现不可变

const startlist=[{id:1,name:'tom'},{id:2,name:'jerry'}]
const [list2,setList2]=useState(startlist);// 列表
function handleUpdate (id, newName) {
        const newlist = list2.map((item) => {
				    if (item.id === id) {
				      return {
				        ...item,
				        name: newName
				      };
				    }
				    return item;
				  });
	 setList2(newlist);
    }
    console.log('startlist', startlist, 'list2', list2);
     const onFirstClick = () => {
        handleUpdate(2, 'xiaoming');
       }

使用深拷贝 -实现不可变。

为list1 创建新的内存地址 即使改变原数组中对象的引用 也不会改变selectList1的值

使用 JSON.parse(JSON.stringify(obj)) 的方式来复制对象

const selectList1 = { title: '大大', value: '1' };
const [list1, setList1] = useState(JSON.parse(JSON.stringify(selectList1)));
list1.title = 'xiaoxiao';
list1.value = '2';
console.log('list1', list1, 'selectList1', selectList1);

使用hook- 实现不可变

const selectList1 = { title: '大大', value: '1' };
const [list1, setList1] = useState(selectList1);// 列表
 useEffect(() => {
 	const newList={ title: 'xiaoxiao', value: '2' }
      setList1(newList);
    }, []);
console.log('list1', list1, 'selectList1', selectList1);
//setList1会新建一个栈给list1赋予值 改变list1的值时 不改变selectList1的值

在 React 中,useState Hook 返回的数组中,第一个元素是状态变量,第二个元素是更新状态的函数。在这个例子中,我们使用了 useState Hook 来定义了一个名为 list1 的状态变量,并将 selectList1 赋值给 list1。

useState Hook 会在内部维护一个状态对象,每次更新状态时,都会创建一个新的状态对象,并用新的对象替换原来的对象。因此,使用 setList1 函数更新 list1 状态时,实际上是将原来的状态对象替换为一个新的状态对象。

当我们修改 list1 状态变量中的属性时,实际上是修改了状态对象的属性。由于 setList1 函数会创建一个新的状态对象,因此修改状态对象的属性并不会影响到 setList1 函数本身,也就是说,setList1 函数并没有进行深拷贝,而仅仅是替换了状态对象的引用,从而实现了对状态变量的更新。

React 的状态更新是异步的,也就是说,状态更新函数并不会立即更新状态变量的值,而是将更新请求加入到一个更新队列中,等到下一次渲染时才会执行状态更新操作。因此,在状态更新函数中使用状态变量的值时,可能会出现不一致的情况,需要特别注意。

需要注意的是,虽然在这个例子中我们可以通过修改状态变量的属性来实现状态更新,但是在 React 中并不推荐这种方式。如果状态变量是一个对象或数组等引用类型,应该使用不可变数据的方式来进行状态更新,以避免出现意外的修改和副作用。

下面介绍几种常用的不可变数据的方式:

在react中 如果不想改变初始值的话 建议使用hook方法进行深拷贝

使用展开运算符(Spread Operator)

  • 对象的例子:

    const [state, setState] = useState({ count: 0, name: 'Tom' });

    function handleClick() {
    setState({
    ...state,
    count: state.count + 1,
    });
    }

在这个例子中,我们使用展开运算符 ... 来创建一个新的对象,新对象包含了原对象的所有属性和方法,同时修改了 count 属性的值。由于我们使用了新的对象来更新状态变量,因此可以实现不可变数据。

  • 数组的例子:

    const [list, setList] = useState(['a', 'b', 'c']);

    function handleAdd() {
    setList([...list, 'd']);
    }

    function handleDelete(index) {
    setList([...list.slice(0, index), ...list.slice(index + 1)]);
    }

  • 使用数组的 map() 方法

可以使用数组的 map() 方法来创建一个新的数组,从而实现不可变数据。

const [list, setList] = useState([{ id: 1, name: 'Tom' }, { id: 2, name: 'Jerry' }]);
 
function handleUpdate(id, newName) {
cosnt newlist=list.map(item => {
    if (item.id === id) {
      return {
        ...item,
        name: newName,
      };
    }
    return item;
  })
  setList(newlist);
}

在使用map进行赋予值时要注意不要直接对list的key进行操作 否则会改变list的值

不可变数据的方式来管理状态的优缺点

可以带来以下优点:

提高性能:由于不可变数据可以避免一些难以发现的错误,并且可以减少不必要的重渲染,从而提高程序的性能。

简化代码:不可变数据可以避免副作用和意外修改,从而简化了代码的编写和维护。

方便调试:不可变数据可以避免一些难以发现的错误,从而方便调试和测试。

不可变数据的方式也存在一些缺点:

需要额外的代码:不可变数据需要创建新的对象或数组,因此需要额外的代码来实现。

需要更多的内存:由于不可变数据需要创建新的对象或数组,因此需要更多的内存来存储。

使用不可变数据的方式来管理状态,其原理是每次对数据进行修改时,都会创建一个新的数据对象,而不是在原始数据上进行修改。这样可以避免在修改数据时意外修改了其他地方引用的相同数据,从而增加了程序的稳定性和可读性。

使用不可变数据的方式,可以通过浅拷贝和深拷贝两种方式来实现。浅拷贝指的是只复制对象或数组的一层属性,而深拷贝则是复制对象或数组的所有属性和方法。在 React 中,可以使用浅拷贝和深拷贝的方式来管理状态,具体的方法包括展开运算符、数组的 map() 方法和库函数等。

博主个人感觉易懂的深拷贝和浅拷贝文章~推荐一波
[文章链接1] [文章链接2]

相关推荐
PandaCave几秒前
vue工程运行、构建、引用环境参数学习记录
javascript·vue.js·学习
软件小伟2 分钟前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js
醉の虾24 分钟前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧32 分钟前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm42 分钟前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep7011 小时前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王2 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue
疯狂的沙粒2 小时前
对 TypeScript 中高级类型的理解?应该在哪些方面可以更好的使用!
前端·javascript·typescript
gqkmiss2 小时前
Chrome 浏览器 131 版本开发者工具(DevTools)更新内容
前端·chrome·浏览器·chrome devtools