原生JS监听事件后修改对象属性,状态无法保留的解决方法
问题
我想在对象被使用时把它的used属性从0改成1,但写了下面的代码后,再次获取同一个对象时,used还是0:
function x() { const array = [{ name: x, surname: y, used: 0 },{ name: c, surname: b, used:0 },{ name: f, surname: g, used: 0 }] const randomNumber = Math.floor(Math.random() * array.length) if (array[randomNumber].used === 0) { array[randomNumber] = { ..., used: 1 }; // 这里的...语法有误,需展开原对象 } }
哪怕对象已经进入过if判断,used值还是没变。我还试了另一种写法:
function x() { const array = [{ name: x, surname: y, used: 0 },{ name: c, surname: b, used:0 },{ name: f, surname: g, used: 0 }] const randomNumber = Math.floor(Math.random() * array.length) if (array[randomNumber].used === 0) { array[randomNumber].used = 1; } }
结果还是一样。请问原生JS里怎么实现类似React的state功能,让修改后的属性值能保留下来?
问题出在哪?
你代码里的array是函数x的局部变量——每次调用x(),都会重新创建一个全新的数组,之前修改的used属性根本存不住,每次调用都是从头开始,数组回到初始状态。
解决方法
1. 把数组移到函数外面(避免每次重建)
把数组放在函数外部,这样它不会随函数调用被重新创建,每次调用函数都是修改同一个数组:
// 把数组放在函数外面,作为持久化的状态 const array = [{ name: 'x', // 注意原代码里的变量x和函数名重名了,建议改成字符串或其他变量 surname: 'y', used: 0 },{ name: 'c', surname: 'b', used:0 },{ name: 'f', surname: 'g', used: 0 }]; function x() { const randomNumber = Math.floor(Math.random() * array.length) if (array[randomNumber].used === 0) { // 直接修改属性就行,或者用展开语法做不可变更新(看需求) array[randomNumber].used = 1; // 不可变写法:array[randomNumber] = {...array[randomNumber], used: 1}; } }
2. 用闭包封装状态(更干净,不污染全局)
用闭包把状态藏在函数内部,只暴露操作方法,和React组件的私有state逻辑类似:
function createPicker() { // 这个数组只会初始化一次,被闭包保存 const array = [{ name: 'x', surname: 'y', used: 0 },{ name: 'c', surname: 'b', used:0 },{ name: 'f', surname: 'g', used: 0 }]; return function() { const randomIdx = Math.floor(Math.random() * array.length); if (array[randomIdx].used === 0) { array[randomIdx].used = 1; } // 返回选中的对象,方便查看结果 return array[randomIdx]; } } // 创建一个实例,每次调用这个实例都会操作同一个状态 const picker = createPicker(); picker(); // 第一次调用,修改某个对象的used为1 picker(); // 第二次调用,可能选中已修改的对象,此时used是1
3. 模拟React的useState(自定义状态管理)
如果想要更贴近React的useState体验,可以自己封装一个简单的状态函数,支持状态更新和读取:
function useState(initialState) { let state = initialState; function setState(newState) { // 支持传入函数计算新状态,和React一致 state = typeof newState === 'function' ? newState(state) : newState; } // 返回获取状态的函数和更新函数 return [() => state, setState]; } // 使用示例 const [getArray, setArray] = useState([{ name: 'x', surname: 'y', used: 0 },{ name: 'c', surname: 'b', used:0 },{ name: 'f', surname: 'g', used: 0 }]); function x() { const currentArray = getArray(); const randomIdx = Math.floor(Math.random() * currentArray.length); if (currentArray[randomIdx].used === 0) { // 不可变更新状态,和React的setState逻辑对齐 setArray(prevArray => { const newArray = [...prevArray]; newArray[randomIdx] = {...newArray[randomIdx], used: 1}; return newArray; }); } }
内容的提问来源于stack exchange,提问作者Jure Ereš
相关产品推荐
相关产品推荐

