это не определено для формы после отправки, но не для кнопки в ответ

Примечание. Этот вопрос не спрашивает, как связать обработчики событий. Он спрашивает, почему без привязки this не соответствует onClick Button (оно относится к объекту) и onSubmit Form (это undefined).

Полный вопрос:

Я пытался проверить, что происходит с объектом this внутри метода, если я не привязываю метод внутри конструктора. Я обнаружил, что результат для формы и кнопки отличается. Ниже приведен мой код для лучшего понимания:

const {Button, Form, Input} = Reactstrap;

class Test extends React.Component{
    constructor(props){
        super(props);
    }

    handleClick(){
        console.log(this);    //This gives complete information about the Button object and its properties 
    }

    handleSubmit(e){
        console.log(this);    //This one is undefined 
        e.preventDefault();
    }

    render(){
        return(
            <React.Fragment>
                <Form onSubmit={this.handleSubmit} >

                <Input type="submit" name="submit">Submit</Input>

                </Form>

                <Button name="butt1" onClick={this.handleClick}>Click</Button>
            </React.Fragment>
        );
    }
}

ReactDOM.render(<Test />, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reactstrap/8.4.1/reactstrap.min.js"></script>

Я проверил, что мой вопрос отличается от этого один, потому что в предоставленном вопросе спрашивающий хочет связать this для компонента, в то время как в моем вопросе я хочу, чтобы this ссылался на форму, точно так же, как он ссылается на кнопку.

Я пытаюсь найти причину такого другого поведения, но мне это не удалось. Не могли бы вы, люди, указать причину того же и предложить способ, чтобы this внутри handleSubmit начинало ссылаться на объект формы?

ИЗМЕНИТЬ Это то, что я считаю причиной, пожалуйста, подтвердите, правильно ли это

Поскольку обработчик отправки был определен с формой, а не с кнопкой отправки, вот почему this не определено, потому что была нажата кнопка отправки, а не форма. Я думаю, мне нужно что-то вроде пузырькового захвата.


person Vipul Tyagi    schedule 13.06.2020    source источник
comment
Я использую webpack и babel для предварительной компиляции, поэтому не думаю, что мне нужны CDN.   -  person Vipul Tyagi    schedule 13.06.2020
comment
^^ Это делается для того, чтобы кому-то другому было проще увидеть, что происходит, чтобы они могли помочь вам лучше. Кстати, по какой причине вы хотите, чтобы это ссылалось на форму, точно так же, как это относится к кнопке. Чего именно вы пытаетесь достичь?   -  person goto1    schedule 13.06.2020
comment
Я просто проверял, что происходит, когда я не привязываю функцию к this. Итак, я получил приведенный выше результат, и мой вопрос заключается в том, почему this не определено после отправки формы, а после нажатия кнопки не определено. Ищу причину такого поведения.   -  person Vipul Tyagi    schedule 13.06.2020


Ответы (1)


Это может показаться ошибкой (или, по крайней мере, несоответствием) в Reactstrap. С обычными элементами form и button React последовательно вызывает обработчики без определенного значения this¹ (так что в этом примере, поскольку код class всегда находится в строгом режиме, мы видим, что this установлено в undefined в вызове):

class Test extends React.Component{
    constructor(props){
        super(props);
    }

    handleClick() {
        console.log(typeof this);
    }

    handleSubmit(e) {
        console.log(typeof this);
        e.preventDefault();
    }

    render(){
        return(
            <React.Fragment>
                <form onSubmit={this.handleSubmit} >

                <input type="submit" name="submit" value="Submit" />

                </form>

                <button type="button" name="butt1" onClick={this.handleClick}>Click</button>
            </React.Fragment>
        );
    }
}

ReactDOM.render(<Test />, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>


Но я читал, что this внутри обычных функций разрешается динамически, т.е. кто его вызвал.

Это неправильно. В обычных функциях и методах значение this внутри вызова определяется вызывающей стороной. Итак, я говорю выше, что React делает одно, а Reactstrap — другое.

Возможно, вы думаете о DOM и о том, как он обрабатывает обработчики событий, что отличается как от React, так и от (очевидно) Reactstrap. DOM вызывает ваш обработчик с this, установленным для элемента, к которому был прикреплен обработчик. Таким образом, если вы прикрепите обработчик к button, и обработчик является обычной функцией или методом, this будет ссылаться на button, когда обработчик вызывается DOM. Это просто то, что делает DOM. Реагировать нет. Reactstrap, по-видимому, различается в зависимости от того, какой это обработчик или какой это элемент (что, вероятно, является ошибкой).

Подробнее о this в ответах на этот вопрос и в этот старый пост в моем анемичном маленьком блоге.


В комментарии вы сказали:

Еще одна вещь, которую я хочу спросить, это как использовать ваш код без строгого режима, потому что он не указывает, какой строгий режим следует использовать.

Есть две причины, по которым код в этом примере находится в строгом режиме:

  1. Как я упоминал ранее в ответе, он находится внутри конструкции class. Код внутри class всегда строгий. (Так же, как и код в модуле JavaScript.)
  2. Он использует Babel для транспиляции JSX, и по умолчанию Babel включает строгий режим в коде, который он выводит.

Итак, чтобы увидеть, что происходит в свободном режиме, вам нужно не использовать class (достаточно просто) и не использовать Babel или, по крайней мере, сказать Babel не включать строгий режим. Я не знаю, есть ли способ запретить Babel использовать строгий режим во фрагментах стека (есть способ, когда вы используете его в реальном мире), но, к счастью, у вас нет использовать JSX с React, это просто удобно. Вы можете использовать React.createElement напрямую:

const {createElement} = React;

function Test() {
    function handleClick() {
        console.log(this === window);
    }

    function handleSubmit(e) {
        console.log(this === window);
        e.preventDefault();
    }

    return createElement(React.Fragment, {
        children: [
            createElement("form", {
                onSubmit: handleSubmit,
                children: [
                    createElement("input", {
                        type: "submit",
                        name: "submit",
                        value: "Submit"
                    })
                ]
            }),
            createElement("button", {
                type: "button",
                name: "butt1",
                onClick: handleClick,
                children: ["Click"]
            })
        ]
    });
}

ReactDOM.render(createElement(Test), document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>

Обратите внимание, что this в обратных вызовах теперь является глобальным this, потому что, когда вы вызываете обычную функцию или метод без определенного значения this в свободном режиме, this в обратном вызове является глобальным this (window в браузерах).


¹ Это даже описано в документации событий React, хотя на самом деле там говорится, что this будет быть undefined. Это верно только в строгом режиме. Технически возможно, но не рекомендуется использовать React без использования строгого режима.

person T.J. Crowder    schedule 13.06.2020
comment
Так должен ли я тестировать эту штуку с обычными формами и кнопками? - person Vipul Tyagi; 13.06.2020
comment
@VIPULTYAGI посмотрите на код, который он включил - он работает, как и ожидалось. - person goto1; 13.06.2020
comment
@VIPULTYAGI - Это зависит от того, что вы хотите протестировать, что делает React или что делает Reactstrap. В документации событий React говорится, что обработчики будут вызываться без конкретных this. (На самом деле это говорит о том, что this будет undefined, но это верно только в строгом режиме. Технически возможно — но не очень хорошая идея — использовать React без использования строгого режима.) Я не знаю Reactstrap, но если они не дают какой-либо гарантии в своей документации, я бы не стал полагаться на значение this в этих обработчиках событий, если вы их не привяжете. - person T.J. Crowder; 13.06.2020
comment
Я протестировал предоставленный вами код, и теперь оба this не определены, как вы сказали. Но я читал, что this внутри обычных функций разрешается динамически, т.е. кто его вызвал. Таким образом, с этой логикой это должно относиться к родительскому объекту, то есть к форме или кнопке. - person Vipul Tyagi; 13.06.2020
comment
Таким образом, это означает, что есть разница в работе реакции и реакции, потому что в моем коде кнопка this не была определена. - person Vipul Tyagi; 13.06.2020
comment
@VIPULTYAGI — с обычными функциями и методами значение this в вызове определяется вызывающим. React отличается от DOM. React вызывает обработчики без установки значения this, поэтому в строгом режиме this внутри вызова равно undefined. DOM вызывает обработчики с this, установленным для элемента, к которому был прикреплен обработчик события. Это просто фундаментальная разница между этими двумя разными вещами, вызывающими ваш код. React делает это одним способом, DOM — другим. - person T.J. Crowder; 13.06.2020
comment
@VIPULTYAGI - Да, это то, о чем я говорил выше. Reactstrap, по-видимому, вызывает ваш обработчик отправки без определенного значения this, но вызывает ваш обработчик кликов с this, установленным для кнопки (как это делает DOM). Каждый из них — React, Reactstrap, DOM — это разные вещи, вызывающие ваши функции, и они делают это по-разному. - person T.J. Crowder; 13.06.2020
comment
Так должен ли я считать такое поведение reactstrap ошибкой?? - person Vipul Tyagi; 13.06.2020
comment
@VIPULTYAGI - Мне кажется, что это несоответствие было непреднамеренным. Но если в документации Reactstrap не сказано, что this будет во время звонка, это не обязательно ошибка. Я недостаточно читал их документацию, чтобы знать, дают ли они какие-либо гарантии в отношении this или что это за гарантии. Если вы это сделаете и ничего не найдете, вы можете поднять проблему в их системе отслеживания проблем (возможно, не используя слово «ошибка»), указав на несоответствие и спросив, является ли поведение преднамеренным и / или какие существуют гарантии. - person T.J. Crowder; 13.06.2020
comment
Еще одна вещь, которую я хочу спросить, это как использовать ваш код без строгого режима, потому что он не указывает, какой строгий режим следует использовать. - person Vipul Tyagi; 13.06.2020
comment
@VIPULTYAGI - я добавил ответ на этот вопрос к ответу выше. - person T.J. Crowder; 13.06.2020
comment
Что я на самом деле пытался сделать, так это то, что я думал, что this будет ссылаться на форму, и тогда я смогу получить все входные значения, используя этот this. Я ошибался. Теперь я буду использовать ref для получения входных значений. - person Vipul Tyagi; 13.06.2020
comment
@VIPULTYAGI лучший способ сделать это — использовать именно то, что есть в документации — reactjs.org/docs/forms.html. Вам не нужны refs или this (за исключением привязки методов вашего класса или просто использования arrow syntax). - person goto1; 13.06.2020