В React, как я могу вызвать событие нажатия пользовательской кнопки из обработчика событий другого компонента? - PullRequest
0 голосов
/ 13 октября 2019

У меня есть приложение React, которое использует Material UI для своего интерфейса. Я создал пользовательский компонент кнопки, который стилизует стандартную кнопку пользовательского интерфейса материала и также использует приставку.

Функция render() моего компонента кнопки выглядит следующим образом:

        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>
        );

Что яхочу, чтобы иметь возможность включить эту кнопку на странице и чтобы пользовательский интерфейс вызывал событие click другим способом, кроме нажатия на нее. Например, в форме входа в систему я хочу, чтобы пользователь, который в настоящее время фокусировался на текстовом поле пароля, мог нажимать кнопку, нажимая клавишу Return / Enter.

Я уверен, что мне нужно использоватьКонцепция пересылки ссылок в React, но я довольно плохо знаком с React и не могу заставить его работать. Вы можете видеть на моей кнопке, что я определил 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 и в конструкторе этой страницы я инициализировал ссылку в конструкторе, используя this.submitButton = React.createRef();

Наконец triggerClick выглядит так:

    triggerClick() {
        console.log('CLICK', this.submitButton.current);
        this.submitButton.current.click();
    }

Когда я нажимаювведите в текстовое поле, я могу проверить значение, присвоенное this.submitButton.current и увидеть, что это объект Redux connect, с которым я обернул свою кнопку. Тем не менее, я также получаю ошибку this.submitButton.current.click is not a function, поэтому ясно, что ссылка не перенаправляется полностью на саму кнопку.

Боюсь, я немного растерялся, поэтому обращаюсь к вам за помощью!

Ответы [ 2 ]

2 голосов
/ 13 октября 2019

Просто хочу убедиться, что вы хотите: когда пользователь нажимает Enter во время набора текста в текстовом поле, кнопка покажет изображение загрузки, верно? Я думаю, вам не нужно передавать ref компоненту button, вы можете просто передать состояние 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 в false в componentWillUnmount

1 голос
/ 13 октября 2019

Я только что попытался воспроизвести ваш случай. И я создал коды и ящик для него. Я думаю, что нашел проблему. Кажется, что 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...