WHAT I HAVE
I have a Parent class and a Child class.
export class Parent {
properties: { x: number};
child: Child;
constructor() {
this.properties = {
x: 1
}
this.child = new Child(this.getX);
}
getX = () => {
return this.properties.x;
}
}
class Child {
parent_getX:()=>string
constructor(parent_getX:()=>string){
this.parent_getX = parent_getX;
}
}
The Parent class has:
properties which stores an number value called x.getX() which simply pulls the value of x from within the properties object.child which holds a reference to a Child object.The Child class only receives a reference to the Parent's getX() function.
WHAT I WANT
My goal is to be able to update the value of x and that everytime I call child.parent_getX() or parent.getX() I get the latest value of x.
WHAT I'M SEEING
I have a React component called Example that takes a Parent object with a an x value of 1 as initial state.
Whenever I increment this value using setState(...) the value of x is incremented but for some reason, parent.getX() and parent.child.parent_getX() always keeps returning the initial value of x. What can I do to keep the function in sync with the parent object?
export const Example = () => {
const [parent, setParent] = useState(new Parent());
const incrementX = ()=>{
let newParent = { ...parent, properties: { ...parent.properties, x: parent.properties.x + 1 } }
setParent(newParent);
}
return (<>
<p>
Parent.properties.x = {parent.properties.x}
<br/>
Parent.getX() = {parent.getX()}
<br/>
Parent.child.parent_getX() = {parent.child.parent_getX()}
</p>
<button onClick={incrementX}>
Increment
</button>
</>);
}
The reason that you are seeing the old values is that in incrementX() you create a copy of the existing Parent instead of instantiating a new one with new (). Therefore, the existing instance of Child (which references the old parent's getX() function) is copied over, as opposed to being instantiated in Parent's constructor. Similarly, the getX() method itself is copied over with it's this referencing the old parent (because it is a fat arrow function, the this reference does not change).
The most straightforward way to fix this is to add a copy constructor to Parent and use that instead of the spread syntax:
export class Parent {
properties: { x: string};
child: Child;
constructor(source?: Parent) {
this.properties = {
x: '1'
}
this.child = new Child(() => this.getX());
if (source) {
this.properties = {...source.properties};
// any additional copy logic goes here
}
}
getX() {
return this.properties.x;
}
}
Then use that copy constructor in your component:
const incrementX = () => {
let newParent = new Parent(parent);
newParent.properties.x = newParent.properties.x + 1;
setParent(newParent);
}
Note that an even easier solution would be to not copy the original Parent at all, and just increment its properties.x, but I'm assuming you need a new instance for the state change to be detected.