javascript - Ascultă modificările unei valori dintr-un obiect în contextul React
Având următorul React Context Provider. O simplă clasă Counter cu 2 metode, stocată în contextul React.
import { createContext, useContext } from "react";
class Counter {
public count: number = 0;
getCount = () => {
return this.count;
};
incrementCount = () => {
this.count = this.count + 1;
};
}
type CounterContextType = {
counter: Counter;
};
const defaults: CounterContextType = {
counter: new Counter()
};
const CounterContext = createContext<CounterContextType>(defaults);
export const CounterProvider: React.FC = ({ children }) => {
const counter = new Counter();
return (
<CounterContext.Provider
value={{
counter
}}
>
{children}
</CounterContext.Provider>
);
};
export const useCounter = () => {
return useContext(CounterContext);
};
Vreau să ascult modificările proprietății count a instanței Counter.
Iată ce am încercat:
import { useMemo } from "react";
import { CounterProvider, useCounter } from "./CounterProvider";
const DisplayWithMethod = () => {
const { counter } = useCounter();
return <div>Method: {counter.getCount()}</div>;
};
const DisplayWithProperty = () => {
const { counter } = useCounter();
return <div>Prop: {counter.count}</div>;
};
const DisplayWithMemo = () => {
const { counter } = useCounter();
const val = useMemo(() => counter.count, [counter.count]);
return <div>Memo: {val}</div>;
};
const Button = () => {
const { counter } = useCounter();
return <button onClick={counter.incrementCount}>Increment</button>;
};
export default function App() {
return (
<CounterProvider>
<DisplayWithMethod />
<DisplayWithProperty />
<DisplayWithMemo />
<Button />
</CounterProvider>
);
}
Niciunul dintre acestea nu funcționează deoarece instanța counter nu se schimbă niciodată, așadar nu se declanșează re-renderizări. Ai vreo idee despre cum să faci ca acest lucru să funcționeze păstrând totodată o structură de clasă pentru Counter?
https://codesandbox.io/s/nostalgic-fast-cyflg
Răspuns #1
Problema este că React nu înțelege că numărul s-a schimbat și nu face rerender. Poți scăpa de problemă folosind hook-ul useState.
Ar trebui să schimbi definițiile de tip ca mai jos și să construiești instanțe de counter folosind output-urile hook-ului useState.
import { createContext, useContext, useState } from "react";
type CounterContextType = {
counter: {
count: number;
getCount: () => number;
incrementCount: () => void;
};
};
const defaults: CounterContextType = {
counter: {
count: 0,
getCount: () => 0,
incrementCount: () => undefined
}
};
const CounterContext = createContext<CounterContextType>(defaults);
export const CounterProvider: React.FC = ({ children }) => {
const [count, setCount] = useState<number>(0);
return (
<CounterContext.Provider
value={{
counter: {
count,
getCount: () => count,
incrementCount: () => {
setCount((prevCount) => prevCount + 1);
}
}
}}
>
{children}
</CounterContext.Provider>
);
};
export const useCounter = () => {
return useContext(CounterContext);
};
Cutie de cod
