javascript - Uppdatera objektets data-medlemmar i React state triggar inte omrendering
Jag använder TypeScript och React för att försöka implementera mina egna typer i en React-komponent. Komponenten renderas dock inte om om objektets datamedlemmar i state har uppdaterats.
Här är min kod:
class Person {
name: string;
surname: string;
constructor(name: string, surname: string) {
this.name = name;
this.surname = surname;
}
}
class App extends Component<AppProps, AppState> {
constructor(props) {
super(props);
this.state = {
persons: [new Person("Alpha", "A"), new Person("Bravo", "B")]
};
}
render() {
return (
<div>
<button
onClick={() => {
this.state.persons[0].name = "Zulu";
this.state.persons[0].surname = "Z";
}}
>
Change A to Z
</button>
<button
onClick={() => {
this.setState({
persons: [...this.state.persons, new Person("Charlie", "C")]
});
}}
>
Add C
</button>
<button onClick={() => { this.forceUpdate(); }}> Force Update </button>
{this.state.persons.map(person => (
<p>
{person.name} {person.surname}
</p>
))}
</div>
);
}
}
Fullständig kodsnutt
Om jag klickar på Change A to Z kommer ingenting att förändras - om inte Add C eller Force Update klickas. Jag antar att React inte kan upptäcka ändringar som görs i Person och därför ingen återrendering sker.
Jag har några frågor om detta problem.
Rekommenderas det att använda detta tillvägagångssätt (anpassad datatyp som state) i React
- Om ja - hur får jag detta att fungera? (React kan upptäcka ändringar gjorda i
Person)
- Om ja - hur får jag detta att fungera? (React kan upptäcka ändringar gjorda i
- Om nej - vad är det rekommenderade sättet att använda egen datatyp i React?
Svar #1
React kommer som standard inte att åter-rendera om varje element i det nya tillståndet är === med varje element i det gamla tillståndet. Du måste också anropa setState för att utlösa en åter-rendering. Din Change A to Z misslyckas på båda punkterna - du måste både skapa en ny persons-array utan att mutera det som för närvarande finns i tillståndet, och sedan anropa setState med den nya arrayen.
Dessutom verkar det inte göra något att ha en Person-instans, eftersom det inte finns några metoder i klassen - och det kommer att göra det svårare att ändra tillståndet, så jag skulle ta bort Person helt. Försök
constructor(props) {
super(props);
this.state = {
persons: [{ name: 'Alpha', surname: 'A' }, { name: 'Bravo', surname: 'B' }]
};
}
Sedan ändra
onClick={() => {
this.state.persons[0].name = "Zulu";
this.state.persons[0].surname = "Z";
}}
till
onClick={() => {
this.setState({
persons: [{ name: 'Zulu', surname: 'Z' }, ...this.state.persons.slice(1)]
});
}}
Den
persons: [{ name: 'Zulu', surname: 'Z' }, ...this.state.persons.slice(1)]
ersätter effektivt på ett oföränderligt sätt det första elementet i arrayen med det nya Zulu-objektet.
Svar #2
Jag har upptäckt att om du uppdaterar vilken variabel som helst, uppdateras skärmen. Jag har inte testat detta grundligt. Men min hypotes är att det enkla sättet att komma runt detta, hur hackigt det än är, är att ha en enkel räkningsvariabel som du bara ökar varje gång du vill uppdatera skärmen.
[counter, setCounter = useState(0);
let updateCounter = (){
setCounter(counter++);
}
sedan när du vill uppdatera skärmen, kalla bara på updateCounter()
Jag kanske kollar igen senare om jag får reda på säkert om den här hacken fungerar eller inte
