how to pass props down using map - reactjs

I'm trying to understand how to pass props down using the map function. I pass down the fruit type in my renderFruits function and in my Fruits sub-component I render the fruit type. I do not understand what is wrong with this code.
import React, { Component } from 'react';
import { render } from 'react-dom';
import Fruits from'./Fruits';
class App extends Component {
constructor(props) {
super(props);
this.state = {
fruits: [
{
type:'apple',
},
{
type:'tomato',
}
]
};
}
renderFruits = () => {
const { fruits } = this.state;
return fruits.map(item =>
<Fruits
type={item.type}
/>
);
}
render() {
return (
<div>
{this.renderFruits}
</div>
);
}
}
render(<App />, document.getElementById('root'));
Fruits component where it should render two divs with the text apple and tomato.
class Fruits extends Component {
render() {
const { type } = this.props;
return(
<div>
{type}
</div>
);
}
}
export default Fruits;

You have two problems in you code
- you should call renderFruits in your render function: this.renderFruits()
- should use "key", when you try to render array
renderFruits = () => {
const { fruits } = this.state;
return fruits.map( (item, index) =>
<Fruits
key={index}
type={item.type}
/>
);
}
render() {
return (
<div>
{this.renderFruits()}
</div>
);
}

Related

Mapping ReactJS list with data from an API.graphql call

I'm trying to map a list with data from an API call to a DynamoDB and I admit, there are many holes in my self-taught JavaScript knowledge.
How do I expose the songList object created in songs = () => {} to my return songList.map?
I've tried with API call outside the component declaration, and in and outside a function.
import React, { Component } from 'react';
import * as queries from '../graphql/queries';
import Song from './Song';
API.configure(awsconfig);
class SongList extends Component {
render() {
const songs = () => {
API.graphql(graphqlOperation(queries.listSongs)).then(function (songData) {
const songList = songData['data']['listSongs']['items'];
return songList;
});
}
console.log(songs()); // undefined
return (
<div>
{
songList.map((song, i) => <Song
key={i}
title={song['title']}
author={song['author']}
keywords={song['keywords']}
instruments={song['instruments']}
isrcCode={song['isrcCode']}
lyrics={song['lyrics']}
/>)
}
</div>
)
}
}
export default SongList;
never NEVER do reqests in render method
componentDidMount(){
const songs = () => {
API.graphql(graphqlOperation(queries.listSongs)).then(function (songData) {
const songList = songData['data']['listSongs']['items'];
return songList;
});
this.setState({list:sondgs()})
}
render() {
let list = this.state.list || []
return (
<div>
{
list.map((song, i) => <Song
key={i}
title={song['title']}
author={song['author']}
keywords={song['keywords']}
instruments={song['instruments']}
isrcCode={song['isrcCode']}
lyrics={song['lyrics']}
/>)
}
</div>
)
}
}

Converting functional component to class component

I have one functional component, but as I need to use now state and more complex logic, I would like to convert it to class component.
But I don't know exactly how to get it working:
My functional component:
import React from 'react';
const FileList = (props) => {
const items = props.items.map((item) => {
return <p key={item.reqId} > { item.name }</ p>
});
return <div>{items}</div>
}
And I tried to do that:
export default class FileL extends React.Component {
constructor(props) {
super(props)
}
render() {
const { items } = this.props;
items = props.items.map((item) => {
return <p key={item.reqId} > {item.name}</ p>
});
return (
<div>{items}</div>
);
}
}
But this is not working.It says "items" is read-only.
I would like to keep the same functionality.
Any ideas?
In your render function
render() {
const { items } = this.props;
items = props.items.map((item) => {
return <p key={item.reqId} > {item.name}</ p>
});
return (
<div>{items}</div>
);
}
items is const so you can't override it. This has nothing to do with React. And you shouldn't reassign a props element, even if its defined with let. You might use the following:
render() {
const { items } = this.props;
return (
<div>
{
items.map((item) => <p key={item.reqId} > {item.name}</ p>)
}
</div>
);
}
You can try this,
export default class FileL extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
{
this.props.items.map((item) => {
return <p key={item.reqId} > {item.name}</ p>
})
}
</div>
);
}
}
Actually you don't need to convert your component to class based component, as React 16.8 comes with Hooks. Using Hooks you can do whatever you can do with class based component. They let you use state and other React features without writing a class.

Reactjs - Props Is Lost While Using It In A Child Component TypeError:

I have the following code in react passes props from stateless component to state-full one and I get TypeError while running.
However, when I use props with same name the error goes away!
Your help would be appreciated in advance
import React, { Component } from 'react';
class App extends Component {
state = {
title:'xxxxxxx',
show:true,
SampleData:[object, object]
}
render() {
const {SampleData} = this.state.SampleData
return (
<div>
<SampleStateless list = {SampleData}/>
</div>
);
}
}
export default App;
const SampleStateless = (props) => {
const {list} = props
return (
<div>
<SampleStatefullComponent secondlist = {list} />
</div>
);
}
class SampleStatefullComponent extends Component {
state = {
something:''
}
render () {
const {secondlist} = this.props
console.log(secondlist);
// I get data correctly in console
const items = secondlist.map (item => return {some js})
//TypeError: secondlist is undefined
return (
<div>
{items}
</div>
)
}
}
You are doing map on a string but map works only on arrays. Take a look at corrected code
Also should be
const {SampleData} = this.state;
but not
const {SampleData} = this.state.SampleData;
Updated code
import React, { Component } from 'react';
class App extends Component {
state = {
title:'xxxxxxx',
show:true,
SampleData:[{'id': "01", "name": "abc"}, {'id': "02", "name": "xyz"}]
}
render() {
const {SampleData} = this.state;
return (
<div>
<SampleStateless list = {SampleData}/>
</div>
);
}
}
export default App;
const SampleStateless = (props) => {
const {list} = props
return (
<div>
<SampleStatefullComponent secondlist = {list} />
</div>
);
}
class SampleStatefullComponent extends Component {
state = {
something:''
}
render () {
const {secondlist} = this.props
console.log(secondlist);
// I get data correctly in console
const items = {secondlist && secondlist.map (item => item.name)}
return (
<div>
{items}
</div>
)
}
}

Pass state value to component

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!
The error is in this component.
const ListSiswa = () => (
<SelectableList>
<Subheader>Daftar Siswa</Subheader>
{this.state.item}
</SelectableList>
);
This component is referred as Stateless Functional Components (Read)
It is simply a pure function which receives some data and returns the jsx.
you do not have the access this here.

ReactJS - ref undefined

I moved away from Alt to Redux and decided to take advantage of context type.
Somewhere in the mix, my ref is now undefined.
What would be the proper procedure for refs to be available with this code:
import React, { Component, PropTypes } from 'react';
// components
import TopNavMenuItem from './top-nav-menu-item';
export default class TopNavZone extends Component {
fetchMenu() {
const results = [];
const navItems = this.context.navItems;
navItems.map((item, index) => {
results.push(
<TopNavMenuItem key={ index }
clientId={ this.context.clientInfo._id }
item={ item }
index={ index }
parent={ this.refs.topNavList }
/>
);
});
return results;
}
render() {
return (
<section>
<nav className="top-nav" id="TopNavZone">
<ul ref="topNavList" className="">
{ this.fetchMenu() }
</ul>
</nav>
</section>
);
}
}
TopNavZone.contextTypes = {
navItems: PropTypes.array.isRequired,
clientInfo: PropTypes.object.isRequired
};
Thank you all.
I captured the ref in ComponentDidMount and made the data part of state instead of calling the function this.fetchMenu from render:
import React, { Component, PropTypes } from 'react';
// components
import TopNavMenuItem from './top-nav-menu-item';
export default class TopNavZone extends Component {
constructor(props) {
super(props); {
this.state = {
results: null
}
}
}
componentDidMount() {
var topNavList = this.refs.topNavList;
this.setState({ results: this.fetchMenu(topNavList) })
}
fetchMenu(topNavList) {
const results = [];
const items = this.context.navItems;
items.map((item, index) => {
results.push(
<TopNavMenuItem key={ index }
clientId={ this.context.clientInfo._id }
item={ item }
index={ index }
parent={ topNavList }
/>
);
});
return results;
}
render() {
return (
<section>
<nav className="top-nav" id="TopNavZone">
<ul ref="topNavList" className="">
{ this.state.results }
</ul>
</nav>
</section>
);
}
}
TopNavZone.contextTypes = {
navItems: PropTypes.array.isRequired,
clientInfo: PropTypes.object.isRequired
};

Resources