深拷贝、浅拷贝 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]

相关推荐
小马哥编程18 分钟前
Function.prototype和Object.prototype 的区别
javascript
小白学前端66619 分钟前
React Router 深入指南:从入门到进阶
前端·react.js·react
web1309332039839 分钟前
前端下载后端文件流,文件可以下载,但是打不开,显示“文件已损坏”的问题分析与解决方案
前端
王小王和他的小伙伴42 分钟前
解决 vue3 中 echarts图表在el-dialog中显示问题
javascript·vue.js·echarts
学前端的小朱1 小时前
处理字体图标、js、html及其他资源
开发语言·javascript·webpack·html·打包工具
outstanding木槿1 小时前
react+antd的Table组件编辑单元格
前端·javascript·react.js·前端框架
好名字08211 小时前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架
摇光932 小时前
js高阶-async与事件循环
开发语言·javascript·事件循环·宏任务·微任务
隐形喷火龙2 小时前
element ui--下拉根据拼音首字母过滤
前端·vue.js·ui
m0_748241122 小时前
Selenium之Web元素定位
前端·selenium·测试工具