I'm building a sidebar menu skeleton using ReactJs and need to understand the way to call a function inside ReactJs render()
function.
The code is below:
import React from 'react';
var menuData = require("./data/admin.menu.json");
class SidebarMenu extends React.Component {
constructor(props) {
super(props);
this.state = { expanded: true };
this.buildItem = this.buildItem.bind(this);
};
buildItem(title, ref, icon) {
return (
<div className={"item" + this.props.key}>
<a href={ref}>{title}<i className={"fa " + icon} /></a>
</div>
);
};
render() {
return (
<div>
{
menuData.forEach(function (item) {
this.buildItem(item.title, item.ref, item.icon);
if (item.hasOwnProperty("submenu")) {
item.submenu.forEach(function (subitem) {
this.buildItem(subitem.title, subitem.ref, subitem.icon);
});
}
})
}
</div>
);
};
}
export default SidebarMenu;
The given code shows the following error:
Uncaught TypeError: Cannot read property 'buildItem' of undefined
How to properly call a function that will render data inside the ReactJs function ?
The this
referenced when you try to call this.buildItem()
refers to the anonymous function's context, not your React component.
By using Arrow Functions instead of functions defined using the function
keyword inside the render()
method, you can use this
to reference the React component and its methods as desired.
Alternatively, you can use (function () { ... }).bind(this)
to achieve the same result. But this is more tedious and the use of arrow functions is preferred.
Below is one solution, using fat arrow, AKA arrow functions:
import React from 'react';
var menuData = require("./data/admin.menu.json");
class SidebarMenu extends React.Component {
constructor(props)
{
super(props);
this.state = { expanded: true };
this.buildItem = this.buildItem.bind(this);
};
buildItem(title, ref, icon) {
return (
<div className={"item" + this.props.key}>
<a href={ref}>{title}<i className={"fa " + item.icon}/></a>
</div>
);
};
render() {
return (
<div>
{
menuData.forEach(item => {
this.buildItem(item.title, item.ref, item.icon);
if (item.hasOwnProperty("submenu"))
{
item.submenu.forEach(subitem => {
this.buildItem(subitem.title, subitem.ref, subitem.icon);
});
}
})
}
</div>
);
};
}
export default SidebarMenu;
Another solution would be:
render() {
return (
<div>
{
menuData.forEach(function (item) {
this.buildItem(item.title, item.ref, item.icon);
if (item.hasOwnProperty("submenu"))
{
item.submenu.forEach(function (subitem) {
this.buildItem(subitem.title, subitem.ref, subitem.icon);
}.bind(this));
}
}.bind(this))
}
</div>
);
};
}
But, IMO, the best solution would be to refactor the code using a component:
import React, {PropTypes, Component} from 'react';
const menuData = require('./data/admin.menu.json');
function MenuItem({key, ref, title, icon, submenu}) {
return (
<div className={`item${key}`}>
<a href={ref}>{title}<i className={`fa ${icon}`}/></a>
if (submenu) {
submenu.map((subitem) => <MenuItem {...subitem} />)
}
</div>
);
}
MenuItem.propTypes = {
key: PropTypes.string,
title: PropTypes.string,
ref: PropTypes.string,
icon: PropTypes.string,
submenu: PropTypes.array,
};
class SidebarMenu extends Component {
constructor(props) {
super(props);
this.state = {
expanded: true,
};
}
render() {
return (
<div>
{
menuData.map((subitem) => <MenuItem {...subitem} />)
}
</div>
);
}
}
export default SidebarMenu;
You can add this line:
render() {
let that = this
return (
and then instead of this.buildItem
use that.buildItem
or you may need that.buildItem.bind(that)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.