简体   繁体   中英

What is the right way to call child component functions in React using React.forwardRef()?

I am new to react and I am trying to build a website. I wanted to trigger a child component function from parent component. ie I have a Dialogbox component and a Navbar component. Onclick event in Navbar( child ) sends props to Display( parent ) and this parent component have to trigger a function in Dialogbox( child ) component to start the dialog box and this Dialogbox have to return me true or false to the parent component based on the user input. And I have managed to do this. The real problem is I get

index.js:1 Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of Transition which is inside StrictMode. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here
    in div (created by Transition)
    in Transition (created by ForwardRef(Fade))
    in ForwardRef(Fade) (created by ForwardRef(Backdrop))
    in ForwardRef(Backdrop) (created by WithStyles(ForwardRef(Backdrop)))
    in WithStyles(ForwardRef(Backdrop)) (created by ForwardRef(Modal))
    in div (created by ForwardRef(Modal))
    in ForwardRef(Portal) (created by ForwardRef(Modal))
    in ForwardRef(Modal) (created by ForwardRef(Dialog))
    in ForwardRef(Dialog) (created by WithStyles(ForwardRef(Dialog)))
    in WithStyles(ForwardRef(Dialog)) (at Dialogbox.js:48)
    in div (at Dialogbox.js:47)
    in AlertDialog (at Display.js:126)
    in div (at Display.js:120)
    in Router (created by BrowserRouter)
    in BrowserRouter (at Display.js:119)
    in Display (at App.js:10)
    in div (at App.js:9)
    in App (at src/index.js:12)
    in StrictMode (at src/index.js:11)

warning in the console. I do not want to ignore this warning. Here is my parent component,

class Display extends React.Component
{

    constructor()
    {
        super()
        this.state = {language: english, changedLang: "null", isBackdrop: false}

        this.DialogRef = React.createRef();

    }

    languageSwitch(changedLanguage)
    {
        if(this.state.language.lang === "en" && changedLanguage === "jp")
        {
            this.setState({changedLang: changedLanguage})
            this.DialogRef.current.handleClickOpen()
            // this.refs.child.handleClickOpen()
        }
        else if(this.state.language.lang === "jp" && changedLanguage === "en")
        {
            this.setState({changedLang: changedLanguage})
            this.DialogRef.current.handleClickOpen()
            // this.refs.child.handleClickOpen()
        }
    }
    agreedOrNot(result)
    {
        if(this.state.language.lang === "en" && this.state.changedLang === "jp")
        {
            if(result)
            {
                this.setState({isBackdrop: true})
                setTimeout(()=> {this.setState({isBackdrop: false})}, 2500)

                setTimeout(()=> {this.setState({language: japanese})}, 2000)
            }
        }
        else if(this.state.language.lang === "jp" && this.state.changedLang === "en")
        {
            if(result)
            {
                this.setState({isBackdrop: true})
                setTimeout(()=> {this.setState({isBackdrop: false})}, 2500)

                setTimeout(()=> {this.setState({language: english})}, 2000)
            }
        }

        return result
    }

    render()
    {
        let backdrop

        if(this.state.isBackdrop)
        {
            backdrop = <LoadingScreen />
        }
        else
        {
            backdrop = <p/>
        }

        return(
            <div>
                <Navbar data={{language: this.state.language, 
                    languageSwitch: this.languageSwitch.bind(this)}} />

                {backdrop}
                    <Dialogbox ref={this.DialogRef} data={{language: this.state.language, 
                    agreedOrNot: this.agreedOrNot.bind(this)}} />

                </div>
        )
    }
}

export default Display

and here is my Dialogbox component.

class AlertDialog extends React.Component 
{
  constructor(props)
  {
    super(props)
    this.state = {open: false, loading: false}

    this.handleClickOpen = this.handleClickOpen.bind(this)
    this.handleCloseFalse = this.handleCloseFalse.bind(this)
    this.handleCloseTrue = this.handleCloseTrue.bind(this)
  }

  handleClickOpen()
  {
      this.setState({open: true})
  }

  handleCloseFalse = () =>
  {
      this.setState({open: false})
      this.props.data.agreedOrNot(false)
  }

  handleCloseTrue = () =>
  {
    this.setState({open: false})
    this.props.data.agreedOrNot(true)
  }

  render()
  {
    let currentLang = this.props.data.language.dialogbox

    return (
      <div>
        <Dialog open={this.state.open} onClose={this.handleClose}
          aria-labelledby="alert-dialog-title" aria-describedby="alert-dialog-description" >

          <DialogTitle id="alert-dialog-title">{currentLang.areYouSure}</DialogTitle>

          <DialogContent>
            <DialogContentText id="alert-dialog-description"> {currentLang.description} </DialogContentText>
          </DialogContent>

          <DialogActions>
            <Button onClick={this.handleCloseFalse} color="primary"> {currentLang.disagree} </Button>
            <Button onClick={this.handleCloseTrue} color="primary" autoFocus> {currentLang.agree} </Button>
          </DialogActions>

        </Dialog>
      </div>
    );
  }
}

export default AlertDialog

The real thing is I have seen the React.forwardRef() implementation in functional components, and the implementations in class are somewhat difficult for me to understand properly. Could someone help me implement React.forwardRef() in classes?

If could, can someone tell me a better way to implement these actions in a much simpler way? If yes, please do the same in my github https://github.com/kishorecmg/kishorecmg

Thank you.

You cannot use a ref on a React component, you can only use it on a DOM element (div, button, input...). You cannot use a ref to trigger a Dialogbox function because the ref cannot be attached to Dialogbox but only to one of the elements rendered by Dialogbox . Therefore handleClickOpen cannot be called. forwardRef won't help either.

One way to solve your problem is to pass a props to the child component and that props can trigger an action

In DialogBox , you can use componentDidUpdate to check if a props has changed and then trigger an action:

componentDidUpdate(prevProps) {
    if (this.props.data.language !== prevProps.data.language) {
        this.setState({open: true})
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM