Call child function in parent with i18next react

1.3k views Asked by At

I used React.createRef() to call child method, like that

import Child from 'child';    

class Parent extends Component {
  constructor(props) {
    super(props);
    this.child = React.createRef();
  }

  onClick = () => {
    this.child.current.getAlert();
  };

  render() {
    return (
      <div>
        <Child ref={this.child} />
        <button onClick={this.onClick}>Click</button>
      </div>
    );
  }
}

Child class like that

    export default class Child extends Component {
      getAlert() {
        alert('getAlert from Child');
      }
    
      render() {
        return <h1>Hello</h1>;
      }
    }

It works well. But when I want to use i18next to translate child component, I have to add withTranslation() to use HOC.

import { useTranslation } from 'react-i18next';
class Child extends Component {
      getAlert() {
        alert('getAlert from Child');
      }
    
      render() {
        const { t } = this.props;
        return <h1>{t('Hello')}</h1>;
     }

    }
export default withTranslation()(Child);

Then return error: Function components cannot be given refs.

Means cannot use ref in <Child /> tag. Is there any way to call child function after add i18next?

1

There are 1 answers

0
Chris On

This is a problem since the withTranslation HOC is using a function component. By wrapping your Child component with a HOC you essentially are placing the ref on the withTranslation component (by default).

There are multiple ways to fix this problem, here are the two easiest:

  1. Using withRef: true >= v10.6.0

React-i18n has a built in option to forward the ref to your own component. You can enable this by using the withRef: true option in the HOC definition:

export default withTranslation({ withRef: true })(Child);
  1. Proxy the ref using a named prop

Instead of using <Child ref={this.child} />, choose a different prop to "forward" the ref to the correct component. One problem though, you want the ref to hold the component instance, so you will need to assign the ref manually in the lifecycle methods.

import Child from 'child';    

class Parent extends Component {
  constructor(props) {
    super(props);
    this.child = React.createRef();
  }

  onClick = () => {
    this.child.current.getAlert();
  };

  render() {
    return (
      <div>
        <Child innerRef={this.child} />
        <button onClick={this.onClick}>Click</button>
      </div>
    );
  }
}
import { useTranslation } from 'react-i18next';
class Child extends Component {
      componentDidMount() {
        this.props.innerRef.current = this;
      }

      componentWillUnmount() {
        this.props.innerRef.current = null;
      }

      getAlert() {
        alert('getAlert from Child');
      }
    
      render() {
        const { t } = this.props;
        return <h1>{t('Hello')}</h1>;
     }

    }

export default withTranslation()(Child);