I am really new in React.js. I wanna pass a state (that i set from api data before) to a component so value of selectable list can dynamically fill from my api data. Here is my code for fetching data :
getListSiswa(){
fetch('http://localhost/assessment-app/adminpg/api/v1/Siswa/')
.then(posts => {
return posts.json();
}).then(data => {
let item = data.posts.map((itm) => {
return(
<div key={itm.siswa_id}>
<ListItem
value={itm.siswa_id}
primaryText={itm.nama}
/>
</div>
)
});
this.setState({item: item});
});
}
From that code, i set a state called item. And i want to pass this state to a component. Here is my code :
const ListSiswa = () => (
<SelectableList>
<Subheader>Daftar Siswa</Subheader>
{this.state.item}
</SelectableList>
);
But i get an error that say
TypeError: Cannot read property 'item' of undefined
I am sorry for my bad explanation. But if you get my point, i am really looking forward for your solution.
Here is my full code for additional info :
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {List, ListItem, makeSelectable} from 'material-ui/List';
import Subheader from 'material-ui/Subheader';
let SelectableList = makeSelectable(List);
function wrapState(ComposedComponent) {
return class SelectableList extends Component {
static propTypes = {
children: PropTypes.node.isRequired,
};
getListSiswa(){
fetch('http://localhost/assessment-app/adminpg/api/v1/Siswa/')
.then(posts => {
return posts.json();
}).then(data => {
let item = data.posts.map((itm) => {
return(
<div key={itm.siswa_id}>
<ListItem
value={itm.siswa_id}
primaryText={itm.nama}
/>
</div>
)
});
this.setState({item: item});
});
}
componentWillMount() {
this.setState({
selectedIndex: this.props.defaultValue,
});
this.getListSiswa();
}
handleRequestChange = (event, index) => {
this.setState({
selectedIndex: index,
});
};
render() {
console.log(this.state.item);
return (
<ComposedComponent
value={this.state.selectedIndex}
onChange={this.handleRequestChange}
>
{this.props.children}
</ComposedComponent>
);
}
};
}
SelectableList = wrapState(SelectableList);
const ListSiswa = () => (
<SelectableList>
<Subheader>Daftar Siswa</Subheader>
{this.state.item}
</SelectableList>
);
export default ListSiswa;
One way to do it is by having the state defined in the parent component instead and pass it down to the child via props:
let SelectableList = makeSelectable(List);
function wrapState(ComposedComponent) {
return class SelectableList extends Component {
static propTypes = {
children: PropTypes.node.isRequired,
};
componentWillMount() {
this.setState({
selectedIndex: this.props.defaultValue,
});
this.props.fetchItem();
}
handleRequestChange = (event, index) => {
this.setState({
selectedIndex: index,
});
};
render() {
console.log(this.state.item);
return (
<ComposedComponent
value={this.state.selectedIndex}
onChange={this.handleRequestChange}
>
{this.props.children}
{this.props.item}
</ComposedComponent>
);
}
};
}
SelectableList = wrapState(SelectableList);
class ListSiswa extends Component {
state = {
item: {}
}
getListSiswa(){
fetch('http://localhost/assessment-app/adminpg/api/v1/Siswa/')
.then(posts => {
return posts.json();
}).then(data => {
let item = data.posts.map((itm) => {
return(
<div key={itm.siswa_id}>
<ListItem
value={itm.siswa_id}
primaryText={itm.nama}
/>
</div>
)
});
this.setState({item: item});
});
}
render() {
return (
<SelectableList item={this.state.item} fetchItem={this.getListSiswa}>
<Subheader>Daftar Siswa</Subheader>
</SelectableList>
);
}
}
export default ListSiswa;
Notice that in wrapState
now I'm accessing the state using this.props.item
and this.props.fetchItem
. This practice is also known as prop drilling in React and it will be an issue once your app scales and multiple nested components. For scaling up you might want to consider using Redux or the Context API. Hope that helps!