在React中,我如何从其他compoennt的事件处理程序中触发自定义按钮的click事件?

时间:2019-10-13 13:45:55

标签: javascript reactjs material-ui

我有一个React应用,其界面使用Material UI。我创建了一个自定义按钮组件,该组件可为默认的Material UI按钮设置样式,并且还使用redux。

我的按钮组件的ActivityLog.XML功能如下:

render()

我想要的是能够在页面上包含此按钮,并使UI通过单击以外的其他方式触发其click事件。例如,在登录表单上,我希望当前专注于密码文本框的用户能够通过单击Return / Enter键来触发按钮单击。

我确定我需要在React中使用转发引用的概念,但是我对React还是很陌生,无法使其正常工作。您可以在我的按钮上看到我已将 return ( <div className={classes.buttonWrapper}> <Button ref={this.props.innerRef} disabled={loading || disabled} onClick={this.handleClick} {...other}> <React.Fragment> {children} {this.buildLoader(loading, classes)} </React.Fragment> </Button> </div> ); 设置为ref。我的按钮组件(称为this.props.innerRef)是这样导出的:

WaitingButton

然后我将此按钮添加到了这样的表单中:

const withInnerRef = React.forwardRef((props, ref) => <WaitingButton 
  innerRef={ref} {...props}
/>);

var component = withStyles(styles)(withInnerRef);

export default connect(mapStateToProps, mapDispatchToProps)(component);

请参阅我已为按钮分配了 <Paper> <TextField style={{marginBottom: '8px'}} label="A textbox!" fullWidth onKeyPress={(e) => { if (e.key === "Enter") this.triggerClick(); }} /> <WaitingButton ref={this.submitButton} variant="contained" color="primary" onClick={(e) => { console.log('Button clicked :)', e.target); }}> Press enter in textbox! </WaitingButton> </Paper> ,并且在此页面的构造函数中,我已使用ref初始化了构造函数中的ref

最后this.submitButton = React.createRef();看起来像这样:

triggerClick

当我在文本框中按下Enter键时,我可以检查分配给 triggerClick() { console.log('CLICK', this.submitButton.current); this.submitButton.current.click(); } 的值,并可以看到它是包装按钮的Redux this.submitButton.current对象。但是,我也收到错误connect,因此很明显,引用并没有一直转发到按钮本身。

恐怕我有点迷失了,所以呼吁您的帮助!

2 个答案:

答案 0 :(得分:2)

仅需确保,您想要的是:当用户在文本字段上键入时按Enter时,该按钮将显示正在加载的图像,对吗? 我认为您不必将ref传递给按钮组件,只需将状态isLoadingShown传递给WaitingButton

WaitingButton.js

 return (
        <div className={classes.buttonWrapper}>
            <Button 
                ref={this.props.innerRef}
                disabled={loading || disabled}
                onClick={this.handleClick}
                {...other}>
                <React.Fragment>
                    {children}
                    {this.props.isLoadingShown && this.buildLoader(loading, classes)}
                </React.Fragment>
            </Button>
        </div>
    );

然后在表单组件中

state = {
   isLoadingShown: false,
}

triggerClick() {
    this.setState({ isLoadingShown: true })
}

render(){
   ...
   <Paper>
       <TextField 
           style={{marginBottom: '8px'}}
           label="A textbox!"
           fullWidth 
           onKeyPress={(e) => { if (e.key === "Enter") this.triggerClick(); }} />
       <WaitingButton
           variant="contained"
           color="primary"
           isLoadingShown={this.state.isLoadingShown}
           onClick={(e) => {
               console.log('Button clicked :)', e.target);
           }}>
           Press enter in textbox!
       </WaitingButton>
   </Paper>
   ...
}

不要忘记在isLoadingShown中将componentWillUnmount再次设置为false

答案 1 :(得分:1)

我只是想重现您的情况。我为此创建了一个codeandbox。我想我找到了问题。看来React.forwardRef仅适用于道具名称forwardedRef,因此请尝试在代码中将innerRef属性重命名为forwardedRef。

const withInnerRef = React.forwardRef((props, ref) => <WaitingButton 
  forwardedRef={ref} {...props}
/>);

以及您的render()函数中

<Button 
    ref={this.props.forwardedRef}
    disabled={loading || disabled}
    onClick={this.handleClick}
    ...

您可以尝试使用我的简化代码和框https://codesandbox.io/s/intelligent-cori-rb5ce