Tengo una clase de frutas:
export class Fruit { constructor(public id: number, public name: string) {} public changeName(_name: string): void { console.log('changing name') this.name = _name } }Y lo implemento así:
import React from 'react' import { Fruit } from '../classes/fruit' const HomePage = () => { let fruit = new Fruit(1, 'apple') return ( <div> {fruit.name} <----- I am expecting this to update on the DOM when i click the button ********* <button onClick={() => fruit.changeName('banana')}> change the name </button> </div> ) } export default HomePagePero cuando hago clic en el botón, el nombre de la fruta en la pantalla no cambia. Se queda como 'manzana'. ¿Alguien sabe lo que estoy haciendo mal? soy nuevo en mecanografiado
Algunas notas:
Los componentes funcionales de React no funcionan así. Si sus datos cambian con el tiempo, debe definir algún estado, con un gancho: const [fruit, setFruit] = React.useState(initialFruit) .
Eso aún no funcionará, ya que su fruit es un objeto mutable, React no "ve" las actualizaciones imperativas en el lugar. No es lo ideal, pero podría engañar a React usando un envoltorio de objeto como valor de estado: { value: someFruit } (esto funciona porque en JS { value: 1 } !== { value: 1 } .
Como puede ver, toda la idea de React implica valores inmutables (también conocido como programación funcional). Considere escribir clases con setters inmutables ( public changeName(name: string): Fruit ), y podrá escribir un buen código declarativo como este: <button onClick={() => setFruit(fruit.changeName('banana'))}> .
export class Fruit { constructor(public id: number, public name: string) {} public changeName(name: string): Fruit { return new Fruit(this.id, name) } }Entonces, aquí está la cosa. Esto no va a funcionar.
En primer lugar, las variables creadas en la función de renderizado de un componente funcional de reacción solo existen durante ese renderizado. Así que cuando lo hagas:
let fruit = new Fruit(1, 'apple') Luego, cada vez que su componente representa, crea una nueva Fruit con una id de 1 con el nombre de "apple" . Cualquier cambio que realice en ese objeto después del renderizado nunca se verá, porque para verlo, el componente necesitaría volver a renderizarse, lo que crea una nueva Fruit desde cero.
La forma de evitar esto es usar "estado" que conserva los valores entre los renderizados de los componentes.
Entonces, en su lugar, digamos que tenías esto:
const HomePage = () => { let [fruit, setFruit] = useState(new Fruit(1, 'apple')) //... }Pero el problema es que se espera que el estado sea inmutable , lo que significa que si el estado cambia, espera un objeto completamente nuevo y está prohibido cambiar una parte del estado.
Esto se debe a que react no puede saber si algo realmente cambia de estado a menos que reemplace el estado por completo.
Entonces, para solucionar eso, necesitaría establecer un objeto nuevo cuando cambie el estado.
Esto debería funcionar:
const HomePage = () => { let [fruit, setFruit] = useState(new Fruit(1, 'apple')) return ( <div> {fruit.name} <button onClick={() => setFruit(new Fruit(fruit.id, 'banana')}> change the name </button> </div> ) }Pero eso es chico de molesto. Esta es la razón por la que no se recomienda poner instancias mutables en estado. Y eso significa que, por lo general, no hay mucha necesidad de instancias de una clase y, por lo general, es mucho más simple almacenar objetos en el estado.
// declare state let [fruit, setFruit] = useState({ id: 1, name: 'apple' }) // set state setFruit({ ...fruit, name: 'banana' })