getting "cannot read property of undefined" with react component written is ES6 - javascript

I'm in the process of learning React. I'm going through a tutorial series that uses ES5. I'm trying to write my components in ES6, which seemed like a straightforward enough process when I was looking at React's documentation about it.
This is the code that is giving me problems:
import React from 'react';
import Button from './button';
import ListItem from './list-item';
export default class DropDown extends React.Component {
constructor() {
super();
this.state = {open: false};
}
handleClick() {
this.state.open = true;
}
render() {
var list = this.props.items.map((item) => {
return <ListItem item={item}/>
});
return (
<div className="dropdown">
<Button onClick={this.handleClick} className='btn-default' title={this.props.title}
subTitleClassName='caret'/>
<ul className={'dropdown-menu ' + (this.state.open ? "show" : "") }>
{list}
</ul>
</div>
)
}
}
I get a TypeError: Cannot read property 'state' of undefined at
handleClick() {
this.state.open = true;
}
whenever I click the button in Chrome.
Could anyone tell me why this is undefined, or what I'm doing wrong?
I should probably mention that I'm using Babelify to transpile it to ES5 as part of my gulp/browserify build process.

The reason why you are getting this error is because 'this' is not autobound for us in es6, as it is in es5 createClass. We can use bind to fix this problem or we can use an arrow function. In your button element, try the following:
<Button
onClick={(e) => this.handleClick(e)}
className='btn-default'
title={this.props.title}
subTitleClassName='caret'
/>

As it was mentioned in the accepted answer, the problem is in binding function to component instance. However, the easiest approach with arrow function isn't always considered the best practice due to creating a new function for Button's prop on every render (that might be sensitive in some optimisation approaches). So you may use binding-in-constructor approach instead:
class Foo extends Component {
constructor(props) {
super(props);
this.methodName = this.methodName.bind(this);
}
methodName(e) {
// handle click
}
render() {
return <Button onClick={this.methodName} />;
}
}
This way you keep render method, which is called by react pretty often, cleaner from build-up code.

Related

New to React - How do I go about fixing/improving this component?

I'm new to the React framework and recently wrote the below code but have been asked to understand what is wrong with it and how I could improve/fix this component.
Please could someone advise a better way of structuring this component and why this approach? Thanks!
class App extends React.Component {  
  constructor(props) {
    super(props);
    this.state = {
      name: this.props.name || 'Anonymous'
    }
  }    
  render() {
    return (
      <p>Hello {this.state.name}</p>
    );  
  }
}
Unless name is supposed to change at some point, your component does not need to be stateful. Simply use the name prop, and use defaultProps to provide the default value:
class App extends React.Component {
render() {
return (
<p>Hello {this.props.name}</p>
)
}
}
App.defaultProps = {name: 'Anonymous'}
You actually don't need to use a class for such a simple component:
function App() {
return (
<p>Hello {this.props.name}</p>
)
}
App.defaultProps = {name: 'Anonymous'}
See the Function and Class Components section for more information about functional vs classes component.
The construction of the state cannot be done that way. You must use componentDidMount() and setState(),
componentDidMount() {
this.setState({
name: this.props.name
});
}
Do you receive some content from an input, or you just want to display this state? If you just wanna display this state, you can just change constructor block with state = { name: 'Anonimus'} and call it in your jsx just as you did.

Best practices for using React refs to call child function

I'm hoping for some clarity on the use of React refs for calling a child function. I have a Parent component that's a toolbar with a few buttons on it, and in the child component I have access to a library's export functionality. I'd like to call this export function on a button click in the parent component. Currently I'm using React refs to accomplish this:
Parent.js [ref]
class Parent extends React.Component {
onExportClick = () => {
this.childRef.export();
}
render() {
return (
<div>
<button onClick={this.onExportClick} />Export</button>
<Child ref={(node) => this.childRef = node;} />
</div>
)
}
}
Child.js [ref]
class Child extends React.Component {
export() {
this.api.exportData();
}
render() {
<ExternalLibComponent
api={(api) => this.api = api}
/>
}
}
This solution works fine, but I've seen a lot of disagreement on if this is the best practice. React's official doc on refs says that we should "avoid using refs for anything that can be done declaratively". In a discussion post for a similar question, Ben Alpert of the React Team says that "refs are designed for exactly this use case" but usually you should try to do it declaratively by passing a prop down.
Here's how I would do this declaratively without ref:
Parent.js [declarative]
class Parent extends React.Component {
onExportClick = () => {
// Set to trigger props change in child
this.setState({
shouldExport: true,
});
// Toggle back to false to ensure child doesn't keep
// calling export on subsequent props changes
// ?? this doesn't seem right
this.setState({
shouldExport: false,
});
}
render() {
return (
<div>
<button onClick={this.onExportClick} />Export</button>
<Child shouldExport={this.state.shouldExport}/>
</div>
)
}
}
Child.js [declarative]
class Child extends React.Component {
componentWillReceiveProps(nextProps) {
if (nextProps.shouldExport) {
this.export();
}
}
export() {
this.api.exportData();
}
render() {
<ExternalLibComponent
api={(api) => this.api = api}
/>
}
}
Although refs are seen as an "escape hatch" for this problem, this declarative solution seems a little hacky, and not any better than using refs. Should I continue to use refs to solve this problem? Or should I go with the somewhat hacky declarative approach?
You don't need to set the shouldExport back to false, you could instead detect the change:
componentWillReceiveProps(nextProps) {
if (nextProps.shouldExport !== this.props.shouldExport) {
this.export();
}
}
Then every toggle of the shouldExport would cause exactly one export. This however looks weird, I'd use a number that I'd increment:
componentWillReceiveProps(nextProps) {
if (nextProps.exportCount > this.props.exportCount) {
this.export();
}
}
I ran into the same problem in many occasions now, and since the React team doesn't encourage it i'll be using the props method for later development, but the problem is sometimes you want to return a value to the parent component, sometimes you need to check the child's state to decide whether to trigger an event or not, therefore refs method will always be my last haven, i suggest you do the same

Calling a function in React

I'm a beginner in React, and I'm a little confused about calling a function in React.
I saw the following ways and I don't know when to use each and which one.
handleAddTodo ={this.handleAddTodo}
handleAddTodo ={this.handleAddTodo()}
handleAddTodo ={handleAddTodo}
handleAddTodo ={this.handleAddTodo}
handleAddTodo ={handleAddTodo()}
Are these interchangeable? Could I do that to handle an event, the same way to call a function?
Are these interchangeable?
Short answer: No.
Let's take a look at the different snippets you've posted:
someFunction() vs someFunction
With the former syntax, you are actually invoking that function. The latter is just a reference to that function. So when do we use which?
You would use someFunction() when you want that function invoked and its result returned immediately. In React, this is typically seen when you split parts of your JSX code to a separate function; either for reasons of readability or reusability. For example:
render() {
myFunction() {
return <p>Foo Bar</p>;
}
return (
<div>
{myFunction()}
</div>
);
}
You would use someFunction when you want only to pass the reference to that function to something else. In React, this is usually an event handler that is passed down to another child-component via props so that that component can call the event handler when it needs to. For example:
class myApp extends React.Component {
doSomething() {
console.log("button clicked!");
}
render() {
return (
<div>
<Button someFunction={this.doSomething} />
</div>
);
}
}
class Button extends React.Component {
render() {
return (
<button onClick={this.props.someFunction}>Click me</button>
);
}
}
someFunction() vs this.someFunction()
This has to do with the context of the function. Basically, "where is this function?". Is part of the current Component, then use this.someFunction(), is it part of the parent Component passed in as props, then use this.props.someFunction(). Is it a function inside the current method, then just use someFunction().
Obviously, there's a lot more to it than that, but it's the best basic summary I can give.
For a better understanding, have a read here. It is a great guide to how the this keyword works in Javascript and in React in particular.
If you want to call a function options 2 and with some assumptions 5 should work.
If you want to actually pass a function as a property to some child component so that it could call it later (say to notify your root element on some event) then option 1 (with prebind) and 3 (with defining a variable const {handleAddTodo} = this and prebind :) ) should work
// this works if handleAddTodo was prebinded or doesn't use this
handleAddTodo ={this.handleAddTodo}
// this probably wont work unless handleAddTodo is higher order function that returns another function
handleAddTodo ={this.handleAddTodo()}
// This wont work unless you have a var/let/const that is referencing a function
handleAddTodo ={handleAddTodo}
// Same as 1
handleAddTodo ={this.handleAddTodo}
// 3 and 2 combined
handleAddTodo ={handleAddTodo()}
To call the function you have to add ()
{this.handleAddTodo()}
About handling events - Handling#Events
Arrow Functions - Functions#ArrowFunctions
In ES6 you can use normal function or Arrow Function:
Function1 (Normal Function)
functionA(){
//Something here
}
Then should call this.functionA()
Function2 (ArrowFunction)
functionA = () => {
//SomeThing Here
}
Then should call this.functionA
*Function3 (Eg: in a const of React) *
const A = (functionTest) =>{
return (
<div>{functionTest}</div>
);
}
functionTest is mapStateToProps in React :)
I hope it is helpful for you :)
this is correct -> handleAddTodo ={this.handleAddTodo}
When function passing to child component you have to bind your function like this handleAddTodo ={this.handleAddTodo.bind(this)}. below code help out your doubt.
Simple Example
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'Initial data...'
}
this.updateState = this.updateState.bind(this);
};
updateState() {
this.setState({data: 'Data updated...'})
}
render() {
return (
<div>
<button onClick = {this.updateState}>CLICK</button>
<h4>{this.state.data}</h4>
</div>
);
}
}
export default App;
Child Events
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 'Initial data...'
}
this.updateState = this.updateState.bind(this);
};
updateState() {
this.setState({data: 'Data updated from the child component...'})
}
render() {
return (
<div>
<Content myDataProp = {this.state.data}
updateStateProp = {this.updateState}></Content>
</div>
);
}
}
class Content extends React.Component {
render() {
return (
<div>
<button onClick = {this.props.updateStateProp.bind(this)}>CLICK</button>
<h3>{this.props.myDataProp}</h3>
</div>
);
}
}
export default App;
Refer here
You can trigger events with this.props.someProps(). Check the following sample.
import React, { Component } from 'react';
class AddToDo extends Component {
render() {
return (
<button onClick={ev => this.props.handleAddToDo(ev, 'hello')}>
{this.props.title}
</button>
)
}
}
class Todos extends Component {
handleAddToDo(ev, someVal) {
// do something
}
render() {
return (
<AddToDo title="Add" handleAddToDo={(ev, someVal) => this.handleAddToDo(ev, someVal)} />
)
}
}
export default Todos;

React - Uncaught TypeError: Cannot read property 'state' of > null

I have the following piece of code. It is basically just a button with an event handler, and the class is supposed to hold some state wich as of now is only a counter, set to 0 initially.
import React, { Component } from 'react';
// import styles from './SentenceView.css';
export default class SentenceView extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
getNextSentence() {
console.log(this.state.count); // this &
this.setState({count: 2}); // this gives me an error
console.log("Executed");
}
render() {
return (
<div>
{/* <div className={styles.container}> */}
<div>
<h1>SentenceView</h1>
<button onClick={this.getNextSentence}>Next Sentence</button>
</div>
</div>
);
}
}
When I click the getNextSentence button I get:
SentenceView.js:14 Uncaught TypeError: Cannot read property 'state' of
null
I am aware that this error is not uncommon, but I have not yet found any solution on here.
Try adding this to your constructor at the bottom:
this.getNextSentence = this.getNextSentence.bind(this);
Component doesn't autobind this on methods like createClass does. You need to bind this to getNextSentence in the constructor (or you can use es7 property initializer syntax to do the binding in the class itself.) Read more here
You need to bind the method to the class in the constructor function and then reference it the same way you are doing in your question in your onClick handler.
constructor(props) {
super(props);
this.state = {
count: 0
};
this.getNextSentence = this.getNextSentence.bind(this);
}
Alternatively, you can bind the function to the SentenceView class.
<button onClick={this.getNextSentence.bind(this)}>
However, as explained by Geoffrey Abdallah in the comment below binding in render will create a new function for every render.
Another option would be to take advantage of ES6's arrow functions in your render method.
<button onClick={() => this.getNextSentence()}>

ReactJS: What do first parameter in addEventListener, ReactDOM.render(), and () mean in return statement?

I'm studying ReactJS and came across the following component example:
class MyComponent extends React.Component {
constructor(props) {
super(props);
// set the default internal state
this.state = {
clicks: 0
};
this.clickHandler = this.clickHandler.bind(this);
}
componentDidMount() {
this.refs.myComponentDiv.addEventListener(
‘click’,
this.clickHandler
);
}
componentWillUnmount() {
this.refs.myComponentDiv.removeEventListener(
‘click’,
this.clickHandler
);
}
clickHandler() {
this.setState({
clicks: this.clicks + 1
});
}
render() {
let children = this.props.children;
return (
<div className=”my-component” ref=”myComponentDiv”>
<h2>My Component ({this.state.clicks} clicks})</h2>
<h3>{this.props.headerText}</h3>
{children}
</div>
);
}
}
What is the first parameter, 'click', mean in this.refs.myComponentDiv.removeEventListener() and this.refs.myComponentDiv.removeEventListener()? And why do you have to pass in props to super()? And what does the () mean in ({this.state.clicks} clicks})?
Lastly, I came across a stateless component:
const StatelessCmp = (props) => {
return (
<div className=”my-stateless-component”>
{props.name}: {props.birthday}
</div>
);
};
// ---
ReactDOM.render(
<StatelessCmp name=”Art” birthday=”10/01/1980” />,
document.getElementById(“main”)
);
And when do you choose to use a stateless component? And when do you use and what does ReactDOM.render() do, especially the document.getElementById(“main”) portion? Because typically, you would simply do export default ....
And in the following, will simply the two <p>'s be displayed on top of the <MyComponent/> class?
<MyComponent headerText=”A list of paragraph tags”>
<p>First child.</p>
<p>Any other <span>number</span> of children...</p>
</MyComponent>
Thank you and will be sure to upvote and accept answer!
'click' is the name of the click event which is created when you click in the viewport/element
As you are extending the class React.Component you have to pass the properties of your class to the super class (React.Component) that it is correctly instantiated. For more infos read a book about Object oriented programming
I cannot find the statement ({this.state.clicks} clicks}) in your code.
If you do not use this.state use a stateless component
ReactDOM.render() actually creates and renders your components to your page. The document.findElementById('main') is looking for the html element with id="main" that ReactDOM can render it into this element.
I would recommend that you read a basic book or take a online tutorial in javascript first before you learn a js framework like React

Categories

Resources