Call child method from parent
First off, let me express that this is generally not the way to go about things in React land. Usually what you want to do is pass down functionality to children in props, and pass up notifications from children in events (or better yet: dispatch
).
But if you must expose an imperative method on a child component, you can use refs. Remember this is an escape hatch and usually indicates a better design is available.
Previously, refs were only supported for Class-based components.
With the advent of React Hooks, that's no longer the case
Modern React with Hooks (v16.8+
)
const { forwardRef, useRef, useImperativeHandle } = React;
// We need to wrap component in `forwardRef` in order to gain
// access to the ref object that is assigned using the `ref` prop.
// This ref is passed as the second parameter to the function component.
const Child = forwardRef((props, ref) => {
// The component instance will be extended
// with whatever you return from the callback passed
// as the second argument
useImperativeHandle(ref, () => ({
getAlert() {
alert("getAlert from Child");
}
}));
return <h1>Hi</h1>;
});
const Parent = () => {
// In order to gain access to the child component instance,
// you need to assign it to a `ref`, so we call `useRef()` to get one
const childRef = useRef();
return (
<div>
<Child ref={childRef} />
<button onClick={() => childRef.current.getAlert()}>Click</button>
</div>
);
};
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>
Call child method from parent class Javascript
Is it a good practice to call child method from a parent class?
Yes, this is totally normal. However, your base class should either provide a default implementation for constructHtml
, or declare it as abstract (in TypeScript). To be precise, it is only a good practice to call methods declared on the class itself, although they might be (or even expected to be) overridden in a subclass.
the call to
this.constructHtml()
returnsundefined
That's because you have a return;
statement doesn't return anything. Remove the linebreak. Don't use Allman brace style in JavaScript.
Call a child method in parent component and change the DOM in the child component
This is because the variable preview
is always null
. Inside the checkProfilePicture
reference function, the if
condition will return false, hence it will trigger setIsPreview(true)
which doesn't really change the isPreview
variable to true. You can try changing that particular setIsPreview
argument to false and you should see that it's really working as expected.
Try this example below:
const {
useState,
useRef,
forwardRef,
useImperativeHandle,
} = React;
const Profilepic = forwardRef(function(props, ref) {
const [preview, setPreview] = useState(null);
const [isPreview, setIsPreview] = useState(true);
useImperativeHandle(ref,() => ({
isPreview,
checkProfilPicture() {
console.log("triggered")
if(preview) {
setIsPreview(true);
console.log("Setting isPreview to true");
return false;
}
else {
setIsPreview(false);
console.log("Setting isPreview to false");
return true;
}
}
}));
return (
<strong>{isPreview.toString()}</strong>
)
});
function Input() {
const profilePicRef = useRef();
const checkAll = () => {
const pr = profilePicRef.current.checkProfilPicture();
};
return (
<div>
<Profilepic ref={profilePicRef}></Profilepic>
<button
onClick={checkAll}>
Speichern & Weiter
</button>
</div>
);
}
function App() {
return (
<Input />
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Why is Typescript calling an overridden child method from within the parent class if I call child.listen()?
this
in a function depends on how it is executed. Here it is executed on child instance so child's setupServer
method will be called.
Regarding the question as to why removing the setupServer
from base class shows an error in TS:
class Base {
listen() {
this.setupServer();
}
}
class Child extends Base {
setupServer() {
console.log("ChildClass")
}
}
const child = new Child();
child.listen();
It is simple, in this case you can anytime create an object from Base Class and that will fail when you call this.listen()
. Typescript cannot let you do that even if setupServer
function is defined later in child class.
Call Child Function from Parent in Reactjs using useRef
You've got this almost right, but typeof Child
is not giving you an accurate type because the Child
component itself is not typed strictly enough. It's getting inferred as forwardRef<unknown, {}>
. We need to specificity the type of the forwarded ref in order for this to work.
We can define an interface for the ref that we want:
interface CanShowAlert {
showAlert(): void;
}
We set the two generics on the forwardRef
function for Child
. CanShowAlert
is the ref type and {}
is the props type:
const Child = forwardRef<CanShowAlert, {}>((props, ref) => {
We use the same generic on the useRef
:
const childRef = useRef<CanShowAlert>(null);
You get an error with your initial value useRef<CanShowAlert>(Child)
because the ref is for an instance of the component, but you are passing in the component function itself. Instead we use null
as the initial value.
The current
property of the ref will either be a component instance or null
, so we need to make sure that it's not null
before we call the showAlert
function. We can use the optional chaining operator ?.
for that.
childRef.current?.showAlert()
Complete code:
import React, {forwardRef, useRef, useImperativeHandle} from "react";
interface CanShowAlert {
showAlert(): void;
}
export default function App() {
const childRef = useRef<CanShowAlert>(null);
return (
<div className="container">
<Child ref={childRef} />
<button
onClick={() => { childRef.current?.showAlert() }}
>
Call Function
</button>
</div>
)
}
const Child = forwardRef<CanShowAlert, {}>((props, ref) => {
useImperativeHandle(
ref,
() => ({
showAlert() {
alert("Child Function Called")
console.log('hello world')
}
}),
)
return (
<div>Child Component</div>
)
})
How to enforce mandatory parent method call when calling child method?
Yeah, it's definitely possible, at least during runtime. U can create a Metaclass
that modifies how classes are created, the idea is to change the necessary_method
signature by adding a mother_method_called
flag that is only going to be true when the Mother
version is called, otherwise it's going to raise a Value Error
. For example in python3
:
class MotherMetaClass(type):
def __new__(cls, name, bases, attrs):
method_name = 'necessary_method'
mother_class_name = 'Mother'
original_necessary_method = attrs.get(method_name)
def necessary_method_validated(*args, **kwargs):
original_necessary_method(*args, **kwargs)
if name == mother_class_name:
cls.mother_method_called = True
else:
if not cls.mother_method_called:
raise ValueError(f'Must call "super()" when overriding "{method_name}".')
cls.mother_method_called = False
attrs[method_name] = necessary_method_validated
return super().__new__(cls, name, bases, attrs)
class Mother(metaclass=MotherMetaClass):
def necessary_method(self):
print('Parent method called.')
class GoodChild(Mother):
def necessary_method(self):
super().necessary_method()
print('Good child method called.')
class BadChild(Mother):
def necessary_method(self):
print("Bad child method called.")
a = GoodChild()
a.necessary_method() # it's going to work properly
b = BadChild()
b.necessary_method() # it's going to raise Value Error
C++ How to call a Child Method from Parent
As you've seen, this code won't compile because A
doesn't have an f
method. In order to make it work, you'd have to explicitly downcast the pointer:
B* tmp = dynamic_cast<B*>(v);
tmp->f();
Can't call child class method from parent class
The way you've written your code, an Inventory
is a type of Soldier
, which doesn't make sense. Instead, a Soldier
should have an Inventory
:
class Soldier:
def __init__(self, name, price, health=100, kills=0, soldier_type='human'):
assert price >= 0
assert health >= 0
assert kills >= 0
assert soldier_type in ('human', 'air', 'ground')
self.name = name
self.price = price
self.health = health
self.kills = kills
self.type = soldier_type
self.inventory = Inventory()
@property
def get_name(self):
return self._name
@get_name.setter
def set_name(self, value):
self._name = value
def get_health(self):
return self.health
def set_health(self, value):
self.health = value
def face_damage(self, value):
self.health = self.health - int(value)
def is_alive(self):
if self.health > 0:
return True
else:
return False
def get_inventory(self):
return self.inventory
class Inventory:
weapon_specs = {
'rifle': {'air': 1, 'ground': 2, 'human': 5},
'pistol': {'air': 0, 'ground': 1, 'human': 3},
'rpg': {'air': 5, 'ground': 5, 'human': 3},
'warhead': {'air': 10, 'ground': 10, 'human': 10},
'machine gun': {'air': 3, 'ground': 3, 'human': 10}
}
def __init__(self):
self.inv = set()
def add_weapon(self, item):
# No need to dedupe since we made this a set instead of a list.
self.inv.add(item)
def get_total_attack(self):
damages = {}
for weapon in self.inv:
for k, v in self.weapon_specs[weapon].items():
damages[k] = damages.get(k, 0) + v
return damages
def get_inventory(self):
return self.inv
def attack(self, total):
# not sure what this is actually supposed to do, but this
# is the closest approximation of what your code was TRYING to do?
return total.values()
def test_p2_4():
soldier = Soldier('ranger', 100)
inventory = soldier.get_inventory()
inventory.add_weapon('rifle')
inventory.add_weapon('machine gun')
inventory.add_weapon('rpg')
damages = inventory.get_total_attack()
assert damages['air'] == 9 and damages['ground'] == 10 and damages['human'] == 18
return "Passed!"
print(test_p2_4())
Related Topics
What Are These Three Dots in React Doing
What Is JavaScript Garbage Collection
Json: Why Are Forward Slashes Escaped
Why Doesn't My Arrow Function Return a Value
Safely Turning a Json String into an Object
How to Get the Value of Text Input Field Using JavaScript
Window.Onload VS $(Document).Ready()
How to Encode a String to Base64 in JavaScript
Difference Between == and === in JavaScript
Get Image Data Url in JavaScript
What Does "Use Strict" Do in JavaScript, and What Is the Reasoning Behind It
Can't Append ≪Script≫ Element
What Do Multiple Arrow Functions Mean in JavaScript
How to Work Around JavaScript'S Parseint Octal Behavior
How Does "This" Keyword Work Within a Function