Eu estou quebrando a regra de imutabilidade. Por isto resolvi fazer esta pergunta. Vou fazer um praralelo de duas formas diferentes de fazer CRUD. Criei dois modelos o mais básico possível
Modelo 1
Acredito que este modelo é o mais utilizado, e diria considerado correto. Cada campo é um state separado. Então pra tudo deve-se trabalhar campo a campo. Como limpar o formulário, transmitir Web Service, receber Web Service. Tudo campo a campo.
Acho que a coisa complica ainda mais com relação a regras de negôcio. A forma de fazer validações, cáculos matemáticos. É um retrocesso na POO.
function App() {
const [codigo, setCodigo] = useState('');
const [descricao, setDescricao] = useState('');
const [un, setUN] = useState('');
return (
<div className="App" style={{ display: 'flex', flexDirection: 'column' }}>
<div>
<label>Código</label>
<input type='text' value={codigo} onChange={(e) => setCodigo( e.target.value)} />
</div>
<div>
<label>Descrição</label>
<input type='text' value={descricao} onChange={(e) => setDescricao( e.target.value)} />
</div>
<div>
<label>UN</label>
<input type='text' value={un} onChange={(e) => setUN( e.target.value)} />
</div>
<div style={{marginTop: "10px"}}>
<label>Teste</label>
<input type='text' value={`${codigo} - ${descricao} - ${un}`} onChange={(e) => e.target.value} />
</div>
</div>
);
}
Modelo 2
É o modelo que estou utilizado. Mas acredito estar ferindo princípios do React. Eu crio uma classe para representar os dados e encapsular as operações como validações e cálculos. Como as propriedades não são states, preciso de um mecanismo que força a renderização. No exemplo abaixo uma instância da classe Produto mantém os dados, e o state "forceRender" força a renderização sempre que uma propriedade munda.
A ideia é ter na classe Produto não só com as propriedade inerentes a ela, ma as ações como validações, etc... É a ideia da POO.
Por exemplo para enviar ou receber um WebService, é simplesmente lidar com uma instância da classe. Não preciso tratar campo a campo
class Produto {
private _codigo: string = '';
private _descricao: string = '';
private _un: string = '';
onchange?: () => void;
performeChange() {
if (this.onchange) {
this.onchange();
}
}
get codigo() {
return this._codigo;
}
set codigo(value: string) {
this._codigo = value;
this.performeChange();
}
get descricao() {
return this._descricao;
}
set descricao(value: string) {
this._descricao = value;
this.performeChange();
}
get un() {
return this._un;
}
set un(value: string) {
this._un = value;
this.performeChange();
}
validate(): string {
if(!codigo || !descricao) {
return 'Informe o código e a desrição.';
}
}
}
function App() {
const [produto, setProduto] = useState(createProduto());
const [forceRender, setforceRender] = useState(0);
function createProduto() {
const result = new Produto();
result.onchange = () => setforceRender(prev => prev + 1);
return result;
}
return (
<div className="App" style={{ display: 'flex', flexDirection: 'column' }} data-force-render={forceRender}>
<div>
<label>Código</label>
<input type='text' value={produto.codigo} onChange={(e) => produto.codigo = e.target.value} />
</div>
<div>
<label>Descrição</label>
<input type='text' value={produto.descricao} onChange={(e) => produto.descricao=e.target.value} />
</div>
<div>
<label>UN</label>
<input type='text' value={produto.un} onChange={(e) => produto.un = e.target.value} />
</div>
<div style={{ marginTop: "10px" }}>
<label>Teste</label>
<input type='text' value={`Objeto: ${produto.codigo} - ${produto.descricao} - ${produto.un}`} onChange={(e) => e.target.value} />
</div>
</div>
);
}
Sugestões
Preciso do comentário de alguém mais experiente do que eu. Posso continuar utilizando o modelo 2? Ou seria melhor abandoná-lo e passar a utilizar o modelo 1?