Reputation: 35
I am new to React and I can't seem to figure this out. I am trying to create dynamic tabs that will display a tab's content when clicked. I am getting a "cannot read property 'handleClick' of undefined" error in the console. Here's what I have so far:
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
tabs: [
{id: 0, name: 'Foo'},
{id: 1, name: 'Bar'},
{id: 2, name: 'Fizz'}
],
contents: [
{name: 'Foo', content: 'Hello'},
{name: 'Bar', content: 'World'},
{name: 'Fizz', content: 'Buzz'},
]
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('Hi');
}
renderTab(tab) {
return(<Tab key={tab.id}
value={tab.name}
onClick={() => this.handleClick()}
/>
);
}
renderContent(i) {
return(<Content content={this.state.contents}/> );
}
render() {
return(
<div className="container-tabs">
<div className="tab">
{this.state.tabs.map(this.renderTab)}
</div>
<div className="tabcontent">
<p>{this.renderContent}</p>
</div>
</div>
) ;
}
}
class Tab extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<button className="tablinks"
onClick={() => this.props.onClick()}>
{this.props.value}
</button>
);
}
}
class Content extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="tabcontent">
{this.props.content}
</div>
);
}
}
ReactDOM.render(
<App/>,
document.getElementById('root')
);
</script>
Upvotes: 0
Views: 7922
Reputation: 21124
There were lots of issues in your app. I fixed all of them and the new App component should be like this. Firstly inside the render method you need to call the two child components render methods using the ()
. Next to the renderContent
function you need to pass one content
instance at a time, not an array. I have posted the App component with all the changes I made to make it work below.
import React, { Component } from 'react';
import Tab from './tab';
import Content from './content';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
tabs: [
{id: 0, name: 'Foo'},
{id: 1, name: 'Bar'},
{id: 2, name: 'Fizz'}
],
contents: [
{name: 'Foo', content: 'Hello'},
{name: 'Bar', content: 'World'},
{name: 'Fizz', content: 'Buzz'},
]
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('Hi');
}
renderTab(tab) {
return(<Tab {...tab}
onClick={this.handleClick}
/>
);
}
renderContent(content) {
console.log(this.state.contents);
return(<Content {...content}/> );
}
render() {
return(
<div className="container-tabs">
<div className="tab">
{this.state.tabs.map(tab => this.renderTab(tab))}
</div>
<div className="tabcontent">
<p>{this.state.contents.map(content => this.renderContent(content))}</p>
</div>
</div>
) ;
}
}
Finally calling the rendertab
function should be as follows. You haven't used map array helper properly.
{this.state.tabs.map(tab => this.renderTab(tab))}
Hope this helps. Happy Coding.
Upvotes: 1
Reputation: 763
Add this to App's constructor this.renderTab = this.renderTab.bind(this);
You are losing App's this
when doing the map in the render method, that's why it says it's not a function.
Upvotes: 1