问题
I am trying to move over the Auth0 login function as described in their tutorial. I am able to get it work if I use it like this:
<button className="btn" onClick={this.props.route.auth.login.bind(this)}>test</button>
but if I set up the button to call a function I define above the render function like this:
login() {
this.props.route.auth.login.bind(this);
}
And change the onclick to be like this:
onClick={this.login()}
or
onClick={() => this.login()}
Then the auth login modal never opens and i receive no error. Also i added a console.log
to login()
and I can see it in the console, but the actual login modal never opens? It works in the first example, but not in the others.
The reason I am attempting to move this into a function is because I would like to pass the login function down into a child component later, and I was unable to do so and I believe this to be the root issue thats preventing me.
回答1:
bind
does not call your function:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called. docs
Also, you are setting the value of onClick
prop to the return value of login
. If you want to pass a reference to the function, you have to do it without the ()
.
Your code should look like this:
<button className="btn" onClick={() => this.login()}>test</button> <!-- You need to keep a reference to `this`, hence the binding -->
Then:
login() {
this.props.route.auth.login();
}
I edited the answer so that it uses an arrow function. However, I prefer not doing that, since it makes the code a bit cumbersome, and rather bind
all the functions in the constructor, like @patrick-w-mcmahon did.
回答2:
Let's say you have a container MyContainer and this container renders a view called MyView. This view has a button that calls a method. MyContainer is going to pass to the MyView the method it needs to use.
MyContainer:
class MyContainer extends React.Component {
constructor(props) {
super(props);
this.myFunc = this.myFunc.bind(this);
}
myFunc() {
console.log("hello world");
}
render() {
return <MyView myClick={this.myFunc}/>;
}
}
MyView:
const MyView = ({ myClick }) => {
return <button onClick={myClick} />;
};
MyView.propTypes = {
myClick: PropTypes.func
};
export default MyView;
You pass the needed function from the container to the view and the view calls its parents function from props. the use of bind() sets this scope to the current scope so that when you call this from a different scope it is going to be the scope of the bind. When you are in the render you run a different scope so you must bind your functions to the current class scope so that this.myReallyCoolFunction() is pointing to the correct scope (your class scope).
回答3:
.bind()
will only bind the object and arguments but won't call (run) the function.
TL;DR Just use .call()
instead of .bind()
instead of .bind()
you can use
.call(this, args)
which is basicaly the same as bind only that call
will call (run) the function.
you could also use .apply()
, which is basicaly the same as .call()
but takes an array with the arguments instead of object like .call()
this way you can avoid arrow functions in you jsx render() and kind of keeping the line of thought with react.
something like ->
login() {
this.props.route.auth.login.call(this);
}
When you call props function through return(JSX) React takes care of calling it once propagation ends.
来源:https://stackoverflow.com/questions/40769724/react-cant-call-prop-function-when-it-is-inside-of-another-function