React useState with ES6 classes



我想创建一个表单,在数据库中保存某种形式的数据模型。

假设我有一门课:

export default class Model {
constructor(model = {}) {
this.x = model.x || '';
this.y = model.y || '';
}
save() {
// code to save 'this' to database
}
}

还有一个组件:

import { React, useState } from 'react';

export const ModelForm = () => {
const [model, setModel] = useState(new Model());
const handleInputChange = (event) => {
const target = event.target;
setModel({ ...model, [target.name]: target.value });
};
const handleSubmit = (event) => {
event.preventDefault();
const modelObject = new Model(model);
modelObject.save();
};
return (
<form onSubmit={handleSubmit}>
<input type='text' name='x' value={model.x} onChange={handleInputChange} />
<input type='text' name='y' value={model.y} onChange={handleInputChange} />
<button type='submit'>Submit</button>
</form>
);
};

这个东西目前正在工作,但我有一个问题。

每次执行setModel时,我都必须销毁model对象并相应地更改值。由于我破坏了它,当我提交表单时,组件中的对象不再是Model对象,而是一个简单的javascript对象。所以,正如你所看到的,我必须创建一个新的来在上面使用save((

我的方法是好的还是有更好的方法?

此外,在useState中使用ES6类是否是一种好的做法?有摔倒的地方吗?

我必须创建一个[new Model]才能在上面使用save()

这当然是一种可行的方法。实际上,您不会在状态中存储Model实例,而只存储构造函数的options对象。将其初始化为简单的

const [model, setModel] = useState({});

(并可能将其重命名为modelArgsmodelOptions(

由于我对其进行了销毁,组件[state]中的对象[…]不再是Model对象,而是一个简单的javascript对象。

它实际上不是析构函数,而是对象文字扩展语法,但是的,您正在setModel调用中创建一个普通对象。

为了解决这个问题,您需要在那里传递一个模型实例——一个新的实例,因为React状态是围绕不变性设计的。不过,你可以很容易地实现这一点:

export default class Model {
constructor(model = {}) {
this.x = model.x || '';
this.y = model.y || '';
}
withUpdate({name, value}) {
// if (!['x', 'y'].includes(name)) throw new RangeError(…)
return new Model({...this, [name]: value});
// or optimised (?):
const clone = new Model(this);
clone[name] = value;
return clone;
}
save() {
// code to save 'this' to database
}
}
const [model, setModel] = useState(new Model());
const handleInputChange = (event) => {
setModel(model.withUpdate(event.target));
};

在我个人看来,我不认为在状态中使用ES6类是个好主意。事实上,在react useState钩子文档中说,如果您需要在组件上有两个状态,则应该放置两个useState钩子。

// If there are too many states, you can use useReducer hook
const [state1, setState1] = useState();
const [state2, setState2] = useState();

我更喜欢使用带有基元值的useState挂钩,因为在React工作时,当您更改状态时,如果新状态的值与旧状态的值相等,则组件不会重新渲染,因为React自己进行比较,但当您使用对象或任何其他非基元值时,即使对象的道具和值相同,对该对象的引用将有所不同,因此它将在不应该渲染的时候重新渲染。请记住,当JavaScript比较非基元值时,它会比较内存中的引用,因此:

const obj1 = {prop: 'a'};
const obj2 = {prop: 'a'};
console.log(obj1 === obj2); // This logs false because they are different objects and they references in memory are not equal
console.log(obj1 === obj1); // This logs true, because its reference is the same.
console.log(obj1.prop === obj2.prop); // This logs true because they are strings (primitive values)

我同意有时在您的状态下拥有es6类是非常有用的。一个不错的解决方案就是创建一个派生变量。

import { React, useState } from 'react';

export const ModelForm = () => {
const [_model, setModel] = useState({});
const model = new Model(_model)
const handleInputChange = (event) => {
const target = event.target;
setModel({ ...model, [target.name]: target.value });
};
const handleSubmit = (event) => {
event.preventDefault();
const modelObject = new Model(model);
modelObject.save();
};
return (
<form onSubmit={handleSubmit}>
<input type='text' name='x' value={model.x} onChange={handleInputChange} />
<input type='text' name='y' value={model.y} onChange={handleInputChange} />
<button type='submit'>Submit</button>
</form>
);
};

最新更新