I want to search for people. An array of data is stored in the redux store. I'm trying to perform a search, but an error occurs.
Cannot read property 'searchInput' of undefined
What could be the problem?
searchHandler(){
console.log('findUser', this.searchInput.value);
this.props.onFindPeople(this.searchInput.value)
}
I add an example code
You lost the context of this to the event handler.
You can either use an arrow function (that uses a lexical context for this):
searchHandler = () => {
console.log("findUser", this.searchInput.value);
this.props.onFindPeople(this.searchInput.value);
}
Or bind it to the class like this:
constructor(props){
super(props);
this.searchHandler = this.searchHandler.bind(this);
}
We do it in the constructor because it will run only once.
You are not binding the function. You need to bind it in constructor like below. Binding is required in order to access this and access state, props and modifying the state.
Please note you need to bind it only in constructor not anywhere else in the component
constructor(props){
super(props);
this.searchHandler = this.searchHandler.bind(this);
}
searchHandler(){
console.log('findUser', this.searchInput.value);
this.props.onFindPeople(this.searchInput.value);
}
Or you can also use arrow function as Sagiv mentioned in his answer.
Related
I am porting this class module example to typescript but i can't set it right the definition of the object reference.
I defined the reference holder as:
private wrapperRef:React.RefObject<HTMLDivElement>
The original handler had to be changed so it uses current property, has this:
if (this.wrapperRef.current && !this.wrapperRef.current.contains(event.target)) {
alert('You clicked outside of me!');
}
but this.wrapperRef.current always comes undefined.
What i am doing wrong?
Here my sandbox.
You aren't creating or setting your ref properly. In a class component, you create the ref with React.createRef():
constructor(props) {
super(props)
this.wrapperRef = React.createRef<HTMLDivElement>()
}
And then assign its value by passing it directly to the ref property of some element.
render() {
return <div ref={this.wrapperRef}>{this.props.children}</div>;
}
Now it should automatically set this.wrapperRef.current after the first render. You don't need the setWrapperRef method at all.
Sandbox
It is a common practice to be bind a user-created method inside a React.Component class.
class App extends React.Component { // simplified example, not actual code
constructor(){
//...
this.logIn=this.logIn.bind(this) // Binding of a method
}
}
Naturally, this is beceause we need to explicitly bind the method to "this class", otherwise we would be referencing with this the window object!
What's however unclear to me, least from the documentation and so on I viewed, if we use in-built life-cycle methods such as render() or componentDidMount(), majority of the code snippets and also the official documentation seem to not explicitly bind to this
class App extends React.Component {
constructor(){
//....
this.componentDidMount = this.componentDidMount.bind(this)
// is there reason why we don't do this ^ ??
}
}
Is there some in-built binding already inside the React.Component we extend?
Or why don't we need to explicitly bind the life-cycle methods (componentDidMount()) like the rest of our created methods (logIn())?
I've made a component with the following:
...
componentDidMount() {
var that = this;
var x = 0;
}
...
render() {
....
<button onClick={this.componentDidMount}>DID MOUNT</button>
....
}
And the results are in -- when the function does initially mount, that is properly bound, but when clicked from the button, it is not.
Which means that the componentDidMount is not already bound, but it is called from the React internals with the proper context so that it doesn't need to be bound.
-- edit
Perhaps also of note: it's worth checking if you use an autobind package, if that binds the lifecycle methods. autobind-decorator in fact does!
Naturally, this is beceause we need to explicitly bind the method to "this class", otherwise we would be referencing with this the window object!
You can also use arrow functions to been able to use this without binding:
sayHello=()=>{
return 'hello';
}
myOtherFunction=()=>{
console.log('I can acces the other function! Say:'+ this.sayHello())
}
And you don't need to bind the life-cycle methods
Edit: As the documentation says in https://reactjs.org/docs/handling-events.html
You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
So it is supposed that lifecycle methods are bound by default.
I looked up what does constructor, super and bind does in General JS.
Example code.
import React from 'react';
class Example extends React.Component {
constructor(props){
super(props);
this.state = { mood: confused }
this.doNothing = this.doNothing.bind(this);
}
doNothing(){} //I really do nothing
render(){
<button onClick={this.doNothing}>I do nothing xD</button>
}
}
Here is what I understand for now
State is an object, in order to create an object within a class I need to use constructor
subclass's constructor will override the parent's constructor, I don't know what is in React.Component but I am sure it is important. I think it is also said in React Document:
Class components should always call the base constructor with props.
super will help me do inherit, and super is the replacement of the parent's constructor. If I need to use this in constructor I need to write super and to go further, I need to pass a parament do super(props) to use this.props
bindwill create a new function that is bounded well with the object, making sure when the function is called, it will be direct to the right object because for some reason if I don't bind it, my button will be like <button onClick={undefined.doNothing}>, because of some class rule :/ (the optional paraments can also help me set pre arguments which are interesting but that isn't what bothers me)
Here is what I don't understand
The meaning of arguments I passed, I have seen some example but they didn't really pass any argument. (The props constructor(props) super(props))
The whole bind code looks odd to me, this.doNothing is changed into what? this.this.doNothing? How does it really works, why my button knows where to find it?
I know this is kinda basic but I did try my best looking things up, I will appreciate if anyone can help me out.
State is an object, in order to create an object within a class I need
to use constructor
You can create whatever object inside a class. Just that state is a special one in React: it need to be defined in constructor to be used in React component life-cycle.
subclass's constructor will override the parent's constructor, I don't
know what is in React.Component but I am sure it is important.
constructor, to my understanding, has three jobs: (1) allows access to this.props by super(props), (2) initialises state and (3) binds functions.
Your later part is on the point.
bindwill create a new function that is bounded well with the object,
making sure when the function is called, it will be direct to the
right object because for some reason if I don't bind it, my button
will be like 'button onClick={undefined.doNothing}>, because of some
class rule
this in React component refers to the component itself. Functions provided by React.Component, e.g. render always have this binding to the component, while your own defined functions don't. So <button onClick={this.doNothing}> in render() will not pose any issue, but doNothing() needs to be bound in constructor to get access to this.
The meaning of arguments I passed, I have seen some example but they
didn't really pass any argument. (The props constructor(props)
super(props))
Look up to point 1. If you use super() instead of super(props), this.props will be undefined inside constructor. It is still accessible in other functions.
Here is the original answer to this.
The whole bind code looks odd to me, this.doNothing is changed into
what? this.this.doNothing? How does it really works, why my button
knows where to find it?
Look up to point 4. this.doNothing().bind(this) allows you to access this inside function doNothing(), including reading state, props and calling other functions of the component. Without binding, this will be undefined inside doNothing().
When you define a variable using the this keyword, it belongs to the scope of the React class and hence can you used throughout the scope of the React class.
The meaning of arguments I passed, I have seen some example but they
didn't really pass any argument.
As far as bind is concerned, .bind takes the context as an argument and returns a function, which when executed will refer to the context of the React class. The rest of the arguments that are passed to bind are made available to the function when it is called.
For example when you write
constructor(props){
super(props);
this.doNothing = this.doNothing.bind(this);
}
The function that is returned by bind is assigned to a variable doNothing which is defined in the class scope. If you change it to
constructor(props){
super(props);
this.someNewFunction = this.doNothing.bind(this);
}
you will use it like
render(){
<button onClick={this.someNewFunction}>I do nothing xD</button>
}
You already set props yourself without knowing:
<button onClick={this.doNothing}>
Here onClick will be set to this.doNothing inside of the props passed to the button constructor. To pass props to your Example class one can do:
<Example color="blue" />
Now in the render method for example you can access it as:
<button style = {{ color: this.props.color }} > Some button </button>
Through that your components can be reused at different places, as the parent can change their props to define their behaviour.
I just started learning React and JavaScript.
While going through the tutorial, I got to this example code of a component, which creates a toggle button:
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
The way I see it, both handleClick and render functions use the class's this object, which is out of their scope (right?).
So why do I only need to bind it into handleClick?
Javascript assigns scope when calling, not when defining. You need to bind() your handleClick() method to the class so that when it's called from the the template it can still access the class' scope via this.
React templates are compiled into javascript functions, so if you didn't bind() your onClick={this.handleClick} handler would be scoped to the template function that called it. In your case, it would refer to the button that was clicked.
If your event handler never referred to this it wouldn't need binding, but since you're calling this.setState() then binding is necessary to keep the handler aware of the class scope.
In any react class, functions like componentWillMount, componentDidMount, render etc are called by react internally while rendering the elements and we never call these methods.
Now since the scope is decided while calling, it's react's job to call/bind these methods with appropriate scope.So we do not need to bother about these functions.
However the other functions like handleClick in above example is a method made by us and react does not know anything about it. Also this method's call is defined by us (i.e. when the button is clicked). So here it is our job to call/bind this method with right scope.
That is why we only bind handleClick and not render function in above example.
I recently started learning React and after attaching a callback to a child element I lost the reference of "this" in the parent element. I am building a simple task and when it is checked. I send it back to the parent so that the parent can delete it and reassign the state to the new array without the element. However, I dont have access to this.state.todosTask. I get undefined.
Below is my code.
Parent Element TodoList
constructor(props){
super(props);
this.state ={
todosTask: props.todos
}
}
handleCheckedTask(task){
console.log("Now Im in the todost"+task)
this.state.todosTask //= Undefined
}
render(){
return(
<div>
<h4>Todo List</h4>
<div className="form-check">
<label className="form-check-label">
{this.state.todosTask.map((todoElement)=>{
return <Todo todo={todoElement} key={todoElement.id} onCheckedTask={this.handleCheckedTask}/>
})}
</label>
</div>
</div>
)
}
Child Component
completed(event){
let self = this
let task = self.props.todo.task
let id = self.props.todo.id
console.log(self.refs.complete)
this.props.onCheckedTask({id:id,task:task})
}
render(){
return(
<div>
<input
className="form-check-input"
type="checkbox"
ref="complete"
onChange={this.completed.bind(this)}/>
{this.props.todo.task}
</div>
)
}
}
You need to bind the handleCheckedTask in the constructor to this.
Explanation: In javascript functions and methods are not bound to the containing object as in other languages, like in Java. In javascript this is dynamic, and it (mostly) means "the caller of the function". For most of the cases, it doesn't make a difference, as normally we call the method through the containing object, as in console.log("foo"). But sometimes, we want to pass the function as a callback, in this case, the caller is not the object where it was defined, but the one that is using the callback. Fortunately we have 2 ways to fix this problem:
Binding the method to an object, with .bind()
Not passing this to the function and get it from the lexical context. (i.e. Using an arrow function).
.
constructor(props){
super(props);
this.state = {
todosTask: props.todos
};
this.handleCheckedTask = this.handleCheckedTask.bind(this);
}
Alternatively you can define your handler using a property initializer.
handleCheckedTask = (task) => {
console.log("Now Im in the todost"+task)
this.state.todosTask //= Undefined
}
You can check the details here
Edit: I removed the part where I said that the caller of the callback was the object that was calling it. Normally for callbacks, this is undefined for normal functions (not arrow functions). For arrow functions this is recovered from the closure, that is, from the lexical context where it was defined.
ES6 does not have automatic this binding. So, this should be bound manually in the constructor.
constructor(props){
super(props);
this.state = {
todosTask: props.todos
};
this.handleCheckedTask = this.handleCheckedTask.bind(this);
}