简体   繁体   中英

“this” is undefined for a form after submit but not for button in react

Note: This question is not asking how to bind the event handlers. It's asking why, without binding , this is not consistent in the Button 's onClick (it refers to an object) and the Form 's onSubmit (it's undefined ).

Full question:

I was trying to check what happens to this object inside a method if I don't bind the method inside the constructor. What I found is that the result is different for Form and Button. Below is my code for better understanding:

 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>

I have checked that my question is different from this one because, in the provided question, the questioner wants to bind this for the component while in my question, I want this to refer to Form, just like it is referring to Button.

I am trying to find the reason for this different behavior, but I couldn't succeed. Can you people please give the reason for the same and suggest a way so that this inside handleSubmit starts referring to Form object?

EDIT This is what I believe the reason is, please confirm if it's correct

Since the handler for submitting was defined with the form, not for the submit button, this is why this is undefined, because submit was clicked, not form. I think I need some bubbling capture like thing here.

It would appear to be a bug (or at least an inconsistency) in Reactstrap . With normal form and button elements, React consistently calls the handlers with no particular this value¹ (so in this example, since class code is always in strict mode, we see this set to undefined in the call):

 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>


But I have read that this inside normal functions is resolved dynamically ie who called it.

That's incorrect. With normal functions and with methods, the value of this within the call is determined by the caller. So what I'm saying above is that React does one thing and Reactstrap does something else.

You may be thinking of the DOM and how it handles event handlers, which is different from both React and (apparently) Reactstrap. The DOM calls your handler with this set to the element the handler was attached to. So if you attach a handler to a button and the handler is a normal function or a method, this will refer to the button when the handler is called by the DOM. It's just something the DOM does. React doesn't. Reactstrap apparently varies depending on what handler it is or what kind of element it is (which is likely a bug).

More about this in this question's answers and in this old post on my anemic little blog .


In a comment you've said:

One more thing that I want to ask is how to use your code without strict mode, because it doesn't specify strict mode to be used

There are two reasons the code in that example is in strict mode:

  1. As I mentioned earlier in the answer, it's inside a class construct. Code inside class is always strict. (So is code in a JavaScript module.)
  2. It's using Babel to transpile the JSX, and by default Babel turns on strict mode in the code it outputs.

So to see what happens in loose mode, you'd have to not use a class (easy enough) and not use Babel, or at least tell Babel not to turn on strict mode. I don't know if there's a way to tell Babel not to use strict mode in Stack Snippets (there is a way when you're using it in the real world), but fortunately, you don't have to use JSX with React, it's just convenient. You can use React.createElement directly:

 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>

Note that this in the callbacks is now the global this , because when you call a normal function or method with no particular this value in loose mode, this within the callback is the global this ( window on browsers).


¹ That's even covered by React's event documentation , although what it actually says is that this will be undefined . That's only true in strict mode. It is, technically, possible — but not a good idea — to use React without using strict mode.

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