Is it possible to get ref of props.children? - reactjs

I want to get ref of Child component. What is the best way to do this?
class Child extends React.Component {
render() {
return <div>Child</div>;
}
}
class GetRef extends React.Component {
componentDidMount() {
console.log(this.props.children.ref)
}
render() {
return this.props.children
}
}
Edit:
So I can use it like this
<GetRef><Child/></GetRef>

I assumed that GetRef children has only one child, then you can retrieve the ref of the only child component with this code
class Child extends React.Component {
render() {
return <div>Child</div>;
}
}
class GetRef extends React.Component {
componentDidMount() {
console.log(this.ref);
}
render() {
const childElement = React.Children.only(this.props.children);
return React.cloneElement(
childElement,
{ ref: el => this.ref = el }
);
}
}
class App extends Component {
render() {
return <GetRef><Child/></GetRef>;
}
}
Here is the complete example on stackblitz
If this.props.children has more than one child, you will need to iterate over the children and store all the refs into an array

This is where forwardRef can be used:
class GetRef extends React.Component {
render() {
console.log(this.props.forwardRef)
}
}
const ref = React.createRef();
<Child forwardRef={ref} />
Alternatively, you may also use:
<Child ref="childRef" .../>
// In the parent component
React.findDOMNode(this.refs.childRef)
But take a look at Exposing DOM Refs to Parent Components to know whether to use ref or not:
In rare cases, you might want to have access to a child’s DOM node from a parent component. This is generally not recommended because it breaks component encapsulation, but it can occasionally be useful for triggering focus or measuring the size or position of a child DOM node.

Related

How to call inherited function in react child component

I have 2 components. One extendind another like this
export default class Parent extends React.Component {
myCustomFunction = () => {
..
this.setState({
myVar: 'pippo'
});
}
}
export default class Child extends Parent {
myCustomFunction = () => {
//I want to call here my parent myCustomFunction
..
this.setState({
myVar: 'pluto',
otherVar: 'paperino'
});
}
render (){
return
<button onClick={this.myCustomFunction } />
}
}
When someone click on button in Child I want to run the Parent function and then do some other stuff on the state.
How can I achieve this without coping the Parent in the Child?
There's lots of approaches but I think you're looking for how to inherit the Parent's function like you would traditionally in any class inheritance model.
class Parent extends React.Component {
constructor() {
super();
}
parentFunc() {
console.log(`Parent`);
}
}
class Child extends Parent {
constructor() {
super();
}
childFunc() {
console.log(`Child`);
super.parentFunc();
}
render() {
return <button onClick={this.childFunc}>Click me</button>;
}
}
CodeSandbox here https://codesandbox.io/s/k3n1664323
MDN docs on super() https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super
p.s. You cannot call super in the context of an arrow function, you will need to use a regular function expression or take a different approach, potentially like the other answer suggested. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

typescript calling connected child ref instance method

to be simple, I have a child component connected by redux
class Child extends React.Component {
foo () {}
}
export default connect()(Child);
and a parent contains it
class Parent extends React.Component {
childRef: React.RefObject<Child> = React.createRef()
bar () {
if (this.childRef.current) {
/*
* here typescript complains that
* Property 'foo' does not exist on
* type 'ConnectedComponentClass<typeof Child...'
*/
this.childRef.current.foo();
}
}
render () {
return (
<Child ref={this.childRef} />
);
}
}
I've tried to set the generic type
<React.ComponentType<Child>>
explicitly when exporting child component, but still not working.
I had the same issue and couldn't find a legitimate solution. I did, however, manage to hack it by redeclaring the child component with type 'any', like so:
class Parent extends React.Component {
childRef: React.RefObject<Child> = React.createRef()
bar () {
if (this.childRef.current) {
const childRef: any = this.childRef.current;
childRef.foo();
}
}
render () {
return (
<Child ref={this.childRef} />
);
}
}
If you ever managed to come up with a better solution i'd like to hear it.

Accessing child refs without passing it from parent

I know I can access a ref for the child like so
ParentComponent extends React.Component {
constructor() {
this.myRef = React.createRef();
}
render() {
return (
<ChildComponent>
<div ref={myRef}>Blah</div>
<ChildComponent>
);
}
}
ChildComponent extends React.Component {
render() {
const {children} = this.props.children;
console.log(children.ref) // Will get DOM element
return {children}
}
}
But is there a way to get the DOM element without passing in the ref from the parent component so that my child component can get the ref from this.props.children?
At a high level i'm trying to make an extensible component ChildComponent so that every parent component that uses ChildComponent doesn't have to declare refs for the child component.
Found an answer here Getting DOM node from React child element
The answer is slightly old so I rewrote a bit of it with callback refs instead of using findDOMNode (https://github.com/yannickcr/eslint-plugin-react/issues/678).
ParentComponent extends React.Component {
constructor() {
this.myRef = React.createRef();
}
render() {
return (
<ChildComponent>
<div ref={myRef}>Blah</div>
<ChildComponent>
);
}
}
ChildComponent extends React.Component {
constructor() {
this.myElement = null;
this.myRef = element => {
this.myElement = element;
};
}
render() {
const {children} = this.props.children;
return (
<div>
{React.cloneElement(children, { ref: this.myRef})};
</div>
)
}
}
Note: the above only works with child component only having child from parent

Higher order component always rerenders ignoring shouldComponentUpdate

I have a higher order component like this
// higherOrderComponent.js
const HigherOrderComponent = Component => class extends React.Component {
shouldComponentUpdate (nextProps, nextState) {
return false
}
render () {
return <Component {...this.props} />
}
}
export default HigherOrderComponent
// myComponent.js
import HigherOrderComponent from './higherOrderComponent'
class MyComponent extends React.Component {
render () {
return <div>my component</div>
}
}
export default HigherOrderComponent(MyComponent)
// parentComponent.js
import MyComponent from './myComponent'
class ParentComponent extends React.Component {
render () {
return <MyComponent />
}
}
I explicitly return false but the component always get re-rendered. Any idea why? I ultimately want to share the "shouldComponentUpdate" across components. How can I achieve that if higher order component does not work?
since you have not specified how you are invoking your Higher Order component, based on the issue I have made a guess how you might be using it.
My Answer is based on the assumption that you are invoking your higher order function like
var MyHigherOrderFn = (HigherOrderComponent(Baar));
If Some you how you can invoke your higher order function like below into return in render, you can avoid the issue.
<HigherOrderComponent prop1="Hello" child="Child" />
Since I don;t know how invoke your function in above way(I am not sure its even possible), I have created HigherOrderComponent2 with different syntax style which can be invoked like, which in turn comply with shouldComponentUpdate
<Parent prop1="val1">
<Child>
</Parent>
import React, {PropTypes} from 'react';
/*This is simeple child component*/
class Baar extends React.Component {
render() {
return (<div>{this.props.name}</div>);
}
}
/*This is your higher order component*/
const HigherOrderComponent = Component => class extends React.Component {
shouldComponentUpdate (nextProps, nextState) {
return false;
}
render () {
return <Component {...this.props} />
}
}
/*This is another way to write higher order component*/
class HigherOrderComponent2 extends React.Component {
constructor(props) {
super(props);
}
shouldComponentUpdate (nextProps, nextState) {
return false;
}
render(){
let child = this.props.children && React.cloneElement(this.props.children,
{...this.props}
);
return <div>{child}</div>
}
}
/*Problem that you are facing how you invoke your Higher Order Compoent*/
export default class Foo extends React.Component {
constructor(props) {
super(props);
this.onHandleClick = this.onHandleClick.bind(this);
this.state={
name: 'Praveen Prasad'
}
}
onHandleClick(){
this.setState({
name:Math.random()
});
}
render() {
{'This is how you might be invoking you higher order component, at this time react render doesnt know it already exists in DOM or not'}
{'this component will always re-render, irrespective of values in shouldComponentUpdate'}
var Baaz = (HigherOrderComponent(Baar));
return (<div>
<button onClick={this.onHandleClick}>Update Name</button>
<Baaz name={this.state.name} />
{'This is another way to invoke higher order Component , and this will respect shouldComponentUpdate'}
<HigherOrderComponent2 name={this.state.name}>
<Baar />
</HigherOrderComponent2>
</div>);
}
}
I have modified your code to create a snippet and it works as intended, MyComponent.render is called only once when shouldComponentUpdate returns false.
My guess is that somehow you are using the unwrapped version of MyComponent instead of the wrapped one. Maybe a problem with your build environment?
// higherOrderComponent.js
const HigherOrderComponent = Component => class extends React.Component {
shouldComponentUpdate (nextProps, nextState) {
return false;
}
render () {
return <Component {...this.props} />
}
}
class MyComponent extends React.Component {
render () {
console.log('render');
return <div>my component</div>
}
}
const MyComponentHOC = HigherOrderComponent(MyComponent);
class ParentComponent extends React.Component {
render () {
return <MyComponentHOC />
}
}
ReactDOM.render(<ParentComponent/>, document.getElementById('container'));
ReactDOM.render(<ParentComponent/>, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
It is about the life cycle for a react component. When a component get initialized, it will not check shouldComponentUpdate. ShouldComponentUpdate will only be called when state/props CHANGED.
FYI the lifecycle methods call in order:
When a component is initialized:
getDefaultProps
getInitialStage
componentWillMount
render
componentDidMount
When a component has state changed:
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
When a component has props changed:
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
When a component is unmounting:
componentWillUnmount
You would need to use a different type of HOC pattern called inheritance inversion to access the lifecycle methods. Since you are overriding shouldComponentUpdate you don't call super however it is required to call super.render() inside the subclassed components render method.
Try this...
const HigherOrderComponent = () => WrappedComponent =>
class ShouldNotUpdate extends WrappedComponent {
shouldComponentUpdate(nextProps) {
return false
}
render() {
return super.render()
}
}
it's good practice to use currying so as you could annotate your classes in the future like...
#HigherOrderComponent
class MyClass extends React.Component {
render() {
return <div>something</div>
}
}
// or without annotations..
const MyNewClass = HigherOrderComponent()(MyClass)

child of the component "this" value and how do I get to parent component?

child of the component "this" value and how do I get to parent component?
ex:
class AComponent extends Component{
static getThis(){
return this;
}
}
class MainComp extends Component{
componentDidMoud(){
console.log(AComponent.getThis());
}
}
in this way, how do I get it?
You shouldn't get the parent component from a child component. If you need to do something (ie affect parent component state), then pass a function from the parent to the child as a prop to do it. If you need to read something, then pass the relevant data from parent to child as a prop to read it.
You can pass props down to children, whether it be a simple primitive value for the child component to use, or a function that can be used by the child component to change the state of the parent component. Here's a simple example.
ParentComponent.js
import React, { Component } from 'react';
import ChildComponent from './ChildComponent';
class ParentComponent extends Component {
constructor(props) {
super(props);
this.state = {
someState: true
};
this.someFunction = this.someFunction.bind(this);
}
someFunction() {
this.setState({
someState: false
});
}
render() {
return (
<ChildComponent aFunc={this.someFunction} aString="someValue"/>
);
}
}
ChildComponent.js
import React, { Component } from 'react';
class ChildComponent extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div className={this.props.aString}>
<button onClick={this.props.aFunc}>
Some text
</button>
</div>
);
}
}

Resources