Reactjs - Cannot read the property of undefined - javascript

I am trying to render a class component using conditional rendering. The class component has a state value that is by default set to false. In the class, a function called start() performs some operation and based on the results, it will call a function verifyTheIdentity() that has setState(). But I am not able to call the verifyTheIdentity() from start().
import React from "react";
import * as faceapi from "face-api.js";
import web3 from "../web3";
class recognize extends React.Component {
constructor(props) {
super();
this.state = {
verified: false
}
this.verifyTheIdentity = this.verifyTheIdentity.bind(this);
// this.start = this.start.bind(this);
}
verifyTheIdentity() {
this.setState(prevState => {
return {
verified: true
}
})
}
async start() {
///////////////////CODE FOR FACE RECOGNITION///////////////////////////////
let name = result.toString();
console.log(name);
const pattern = new RegExp(/^unknown/)
console.log(pattern.test(name))
if (pattern.test(name) === false) {
document.getElementById("verifier").disabled = false;
document.getElementById("verifier").onClick = this.verifyTheIdentity; //This is where I am going wrong.
}
else
document.getElementById("verifier").disabled = true;
})
})
}
render() {
return (
<div>
{this.state.verified == false ? <div><br /><br /><br /><br />
<input type="file" id="imageUpload" /><br />
<button disabled id="verifier" >Verify</button></div> :
<div><br /><br /><br /><br /><p>Verified</p></div>}
</div>
)
}
}
export default recognize;
And this is the error I get.
Unhandled Rejection (TypeError): Cannot read property
'verifyTheIdentity' of undefined.

First of all, you do not need bind at all, if you use arrow function.
constructor(props) {
super();
this.state = {
verified: false
}
}
verifyTheIdentity = () => {
//code
}
start = async () => {
// code
}
Try this, it should work.
or
remove commented code,
add in constructor (remove // from the line)
this.start = this.start.bind(this);

you can replace this line by below one
document.getElementById("verifier").onClick = this.verifyTheIdentity;
like this
document.getElementById("verifier").onClick = this.verifyTheIdentity();

The issue is related to Javascript Syntax violation -
"Calling a function without parenthesis"
To fix the issue, either call the function verifyTheIdentity() with proper syntax as:
document.getElementById("verifier").onClick = this.verifyTheIdentity();
Or, assign the function to a varialbe and call it:
const test = verifyTheIdentity() {
this.setState(prevState => {
return {
verified: true
}
})
};
document.getElementById("verifier").onClick = this.test ;
For your understanding, see the example:
function Test(){
alert(1);
}
//Test; //It won't work
Test(); // It will work

Related

Undefined is not an object only for some variables in my constructor

I have a pretty straightforward problem, but I can't see to figure out why it happens. I have a component in which I declare two arrays in my constructor:
class FilterModal extends Component {
constructor(props) {
super(props);
this.transport_options = ["driving", "tram", "walking"];
this.pressed_percentages = ["allPressed", "under15Pressed","under30Pressed", "over30Pressed"];
filters = {
"driving": {
"allPressed":false,
"under15Pressed":false,
"under30Pressed":false,
"over30Pressed":false
},
"tram": {
"allPressed":false,
"under15Pressed":false,
"under30Pressed":false,
"over30Pressed":false
},
"walking": {
"allPressed":false,
"under15Pressed":false,
"under30Pressed":false,
"over30Pressed":false
},
"isFilterActive": false
}
//state declared here
}
}
I want to access the variables transport_options and pressed_percentages in a function that I define after the constructor:
resetPressed = () => {
this.transport_options.forEach(function (transport_option) {
this.pressed_percentages.forEach(function (pressed_percentage) {
filters[transport_option][pressed_percentage] = false;
})
});
//additional business logic
}
My problem is this: when I call resetPressed, I get the message "undefined is not an object (evaluating 'this.pressed_percentages'). However, this.transport_options does not trigger any error message.
So my question is: why does this.transport_options work, but this.pressed_percentages throws an error?
Can you also share the code where you have called this function?
Looks like this scope is changed
This must be the issues, in which your function is not binded. try using arrow operator to define your function or use bind function as it is used in following example.
class App extends React.Component {
constructor(props) {
super(props);
this.transport_options = ["driving", "tram", "walking"];
this.pressed_percentages = ["allPressed", "under15Pressed","under30Pressed", "over30Pressed"];
this.filters = {
"driving": {
"allPressed":false,
"under15Pressed":false,
"under30Pressed":false,
"over30Pressed":false
},
"tram": {
"allPressed":false,
"under15Pressed":false,
"under30Pressed":false,
"over30Pressed":false
},
"walking": {
"allPressed":false,
"under15Pressed":false,
"under30Pressed":false,
"over30Pressed":false
},
"isFilterActive": false
}
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log(this.transport_options)
}
render() {
return (
<button onClick={this.handleClick}>
click me
</button>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
In callbacks also you have to bind your functions, like this.
resetPressed = () => {
this.transport_options.forEach((transport_option)=> {
this.pressed_percentages.forEach((pressed_percentage) =>{
this.filters[transport_option][pressed_percentage] = false;
})
});
//additional business logic
}
For more explanation please refer event handling react

React Classes: Referencing class as "this", within an object's function property

I have finally gotten into using react and ES6 and it's going well but I am finally stumped and could use some direction.
I have got my head around binding this to a method to reference the class, but I am trying to go a bit deeper. Take this for example...which works as expected:
class App extends Component {
state = {
myFirstState: false,
};
handleMyFirstState = () => {
this.setState( { myFirstState : true } );
};
render() {
return (
<MyComponent handleMySate={ this.handleMyState } />
);
}
}
export default App;
As the amount of methods increased I decided NOT to pass each method individually as props and to group them in an object first, and to just pass the object as a whole, as a prop. Like So...
class App extends Component {
state = {
myFirstState: false,
mySecondState: false
};
handleMyFirstState = () => {
this.setState( { myFirstState : true } );
};
handleMySecondSate = () => {
this.setState( { mySecondState : true } );
};
render() {
const handleStates = {
first : this.handleMyFirstState,
second : this.handleMySecondState
}
return (
<MyComponent handleStates={ handleStates } />
);
}
}
export default App;
Now, I am trying to avoid redundant code and just build the methods as one object with functions as properties before the render begins. Pretty much like this...
class App extends Component {
state = {
myFirstState: false,
mySecondState: false
};
handleStates = {
// Here is where 'this' does not reference the App class
// I get results from the console log but setstate doesn't pass correctly
first : () => { console.log("First Triggered"); this.setState( { myFirstState : true } ); },
second : () => { console.log("Second Triggered"); this.setState( { mySecondState : true } ); }
};
render() {
return (
<MyComponent handleStates={this.handleStates} />
);
}
}
export default App;
// I trigger the function like this within MyComponent and I get the console log, but `this.setState` breaks.
<Button onClick={ this.props.handleState.first } >Handle First</button>
I have successfully triggered the functions from the child component ,<MyComponent/>, using the latter code, but this no longer refers to the class and I can't figure out how to bind this to handleStates since it's not a function.
Is this just not possible or is there another way to handle what I am trying to achieve?
Thank you in advance!
ADDITIONAL
If I move the handleStates into the render() it works just fine...how could that be?
class App extends Component {
state = {
myFirstState: false,
mySecondState: false
};
render() {
const handleStates = {
first : () => { this.setState( { myFirstState : true } ); },
second : () => { this.setState( { mySecondState : true } ); }
};
return (
<MyComponent handleStates={this.handleStates} />
);
}
}
export default App;
First, in the second example, you pass this.handleStates as the value for the prop handleStates, but it's undefined. You built handleStates as a local variable, and thus you want your props to reference that local variable:
<MyComponent handleStates={handleStates} />
For your third (last) example, your issue is even simpler: you defined handleStates as an attribute on this which is assigned an object, itself with two attributes, first and second, each of which have a function as their value.
When you ultimately pass this.handleStates to MyComponent, you're passing an object, not a function. If you want to call one of first or second from MyComponent, you can do so like this:
this.props.handleStates.first()
Which has the desired result of updating the state in App.
For what it's worth, there's a more common pattern for this: simply pass a single updater function as the prop, named according to what it does:
class Sandwich extends React.Component {
this.state = {
bread: "",
meat: "",
veggie: "",
}
updateSandwich = (component, selection) => {
this.setState({ [component]: selection })
}
render() {
return(<IngredientSelector updateSandwich={this.updateSandwich} />)
}
}
class IngredientSelector extends React.Component {
return(){
<button value="Rye" onClick={() => this.updateSandwich("bread", "rye")} />
<button value="Wheat" onClick={() => this.updateSandwich("bread", "wheat")} />
<button value="Ham" onClick={() => this.updateSandwich("meat", "ham")} />
<button value="Turkey" onClick={() => this.updateSandwich("meat", "turkey")} />
}
}

Why are some of them "funcName()" and some of them "funcName = () =>"?

When we translated the previous code to ES2015 syntax, some functions got converted to a different syntax. Some of them are funcName() and some of them are funcName = () =>. What's the difference?
import React, { Component, PropTypes } from 'react';
export default class Stopwatch extends Component {
state = {
running: false,
previouseTime: 0,
elapsedTime: 0,
}
componentDidMount() {
this.interval = setInterval(this.onTick);
}
componentWillUnmount() {
clearInterval(this.interval);
}
onStart = () => {
this.setState({
running: true,
previousTime: Date.now(),
});
}
onStop = () => {
this.setState({
running: false,
});
}
onReset = () => {
this.setState({
elapsedTime: 0,
previousTime: Date.now(),
});
}
onTick = () => {
if (this.state.running) {
var now = Date.now();
this.setState({
elapsedTime: this.state.elapsedTime + (now - this.state.previousTime),
previousTime: Date.now(),
});
}
}
render() {
var seconds = Math.floor(this.state.elapsedTime / 1000);
return (
<div className="stopwatch" >
<h2>Stopwatch</h2>
<div className="stopwatch-time"> {seconds} </div>
{ this.state.running ?
<button onClick={this.onStop}>Stop</button>
:
<button onClick={this.onStart}>Start</button>
}
<button onClick={this.onReset}>Reset</button>
</div>
)
}
}
funcName() in a JavaScript class will add a function to the prototype. These functions will exist only once, attached to the prototype. Without the class syntax you would define a prototype function as follows:
Stopwatch.prototype.funcName = function() { /* ... */ };
The other functions are actually created as properties that contain anonymous functions that exist once per each instance and are created in the constructor when the class is instantiated. This is equivalent to creating them in the constructor as below:
class Stopwatch /* ... */ {
constructor() {
this.onStart = () => { /* ... */ };
}
}
The reason for doing this is that using the => syntax to create the functions causes the functions to be permanently bound to the this value of each instance. Therefore they can be passed around to other things (such as set as event handlers) and when they are called, this will always point to the correct object inside the function.
Whether this is a good idea or just plain unreadable/too tricky is perhaps a matter of taste.

React - Can't set state using Axios with GitHub API

trying to set up a simple AJAX call with Axios in React.
I make the Axios call in my 'FetchRepos' component then require it in my 'Homepage' component passing a language argument.
It loads fine because I console.logged the data in Homepage component but when I put the function in set state I check in React dev tools and the 'repos' state is null and when I do the onClick method for 'activeLanguage' it simply removes 'repos' from state.
Help would be appreciated.
Homepage Component
import React from "react";
import {fetchPopularRepos} from "./FetchRepos";
class Homepage extends React.Component {
constructor(props) {
super(props);
this.state = {
activeLanguage: 'all',
repos: null
}
this.activeLanguage = this.activeLanguage.bind(this);
}
activeLanguage(lang) {
this.setState({
activeLanguage: lang,
repos: fetchPopularRepos(lang)
})
}
render() {
var languages = ['all', 'ruby', 'javascript', 'python'];
return (
<div>
{languages.map((lang) => {
return (
<li key={lang} onClick={this.activeLanguage.bind(null, lang)} style={lang === this.state.activeLanguage ? {color: 'red'} : null}>{lang}</li>
)
})}
</div>
)
}
}
FetchRepos Component
var axios = require('axios');
export function fetchPopularRepos(language) {
axios.get('https://api.github.com/search/repositories?q=stars:>1+language:'+ language + '&sort=stars&order=desc&type=Repositories')
.then(function(res) {
return res.data.items;
})
}
You have 2 problems here:
1- The axios function return a promise, so even with the promise your state won't be set up correctly. You must use asyn/await or handle the respond as a promise and set up the state inside a then function.
async activeLanguage(lang) {
this.setState({
activeLanguage: lang,
repos: await fetchPopularRepos(lang)
})
}
2- You must return something from the fetchPopularRepos function because your function is not returning anything. See my code below
BAD (Does not return any value)
function some(){
var a = 1;
var b = 2;
var result = a + b
}
GOOD (Return a value)
function some(){
var a = 1;
var b = 2;
return a + b
}
So, you return something because you want to catch whatever is the result in other piece of your code. Like this:
ver result = some()

Passing a function down multiple children components in React using ES6

I have a LayoutComponent, PageComponent, and SingleComponent.
When my user clicks a button, I want to display a message to the user on a NewPageComponent that my application routes to using Meteor's FlowRouter.
To do this, I am storing the message in LayoutComponent's state, and then passing this message and a handlerMethod down as props to the SingleComponent via PageComponent, which is a stateless functional component.
I am not having any luck passing the handlerMethod down properly to the SingleComponent in order to set the message state on LayoutComponent.
I know this is a simple syntax issue, but could someone help me find my error?
LayoutComponent:
export default class LayoutComponent extends Component {
constructor() {
super();
this.state = {
message: null
};
this.handlerMethod = this.handlerMethod.bind(this);
}
handlerMethod(message) {
this.setState({ message: message });
}
render() {
// the PageComponent is actually passed via FlowRouter in this.props.content, so it needs to be cloned to add props
let contentWithProps = React.cloneElement(this.props.content, { message: this.state.message, handlerMethod: ((message) => this.handlerMethod) });
return (
<div>{contentWithProps}</div>
);
}
}
PageComponent:
const PageComponent = ({ message, handlerMethod }) => {
return (
<div>
<SingleComponent message={message} handlerMethod={(message) => handlerMethod} />
</ div>
);
}
Component:
export default class SingleComponent extends Component {
constructor() {
super();
this.state = {
};
this.handleButtonClick = this.handleButtonClick.bind(this);
}
handleButtonClick(event) {
event.preventDefault();
// do some more stuff...
this.props.handlerMethod("You pressed the button!");
FlowRouter.go("newPage");
}
render() {
<div>
<button onClick={this.handleButtonClick}>button</button>
</div>
}
}
You aren't actually calling your handlerMethod in the code you posted. So this:
handlerMethod: ((message) => this.handlerMethod)
Should be either:
handlerMethod: ((message) => this.handlerMethod(message))
Or more simply:
handlerMethod: this.handlerMethod
Your mistake is that you're passing a function that will return this.handlerMethod instead of call it:
handlerMethod: ((message) => this.handlerMethod) // this returns the handlerMethod function, doesn't call it
Should be
handlerMethod: ((message) => this.handlerMethod(message))
You can also pass it directly:
handlerMethod: this.handlerMethod
The reason passing it directly works is because you're binding the context of handlerMethod inside the constructor for LayoutComponent, meaning this inside handlerMethod will be fixed to LayoutComponent (see Note bellow)
Here's a short example:
Layout Component
export default class LayoutComponent extends Component {
constructor() {
// ...
this.handlerMethod = this.handlerMethod.bind(this); // handler is bound
}
handlerMethod(message) {
// ...
}
render() {
let contentWithProps = React.cloneElement(
this.props.content, {
message: this.state.message,
handlerMethod: this.handlerMethod // pass the handler directly
}
);
return <div>{contentWithProps}</div>;
}
}
Page Component
// pass the handlerMethod directly
const PageComponent = ({ message, handlerMethod }) => {
return (
<div>
<SingleComponent message={message} handlerMethod={handlerMethod} />
</ div>
);
}
Single Component
export default class SingleComponent extends Component {
// ...
handleButtonClick(event) {
// ...
this.props.handlerMethod("You pressed the button!"); // call the passed method here
// ...
}
// ...
}
Note: Technically, you could override bound this by calling new this.handlerMethod but this isn't happening so you're fine.
If you simply want to pass the method down, you do it like this:
const PageComponent = ({ message, handlerMethod }) => {
return (
<div>
<SingleComponent message={message} handlerMethod={handlerMethod} />
</ div>
);
}

Categories

Resources