Mapping ReactJS list with data from an API.graphql call - reactjs

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>
)
}
}

Related

React - error result map is not a function?

Framework: React
Error type: result.map is not a function
I am following the book Road to learn React, I tried the below code with hacker news API it worked well but it is not working with this API. I don't know why I'm getting this error, please help.
Link to my sandbox --> https://codesandbox.io/s/react-setup-forked-q0hti?file=/src/App.js
import React, { Component } from "react";
// API chunks
const PATH_BASE = "https://jsonplaceholder.typicode.com/todos";
const PATH_SEARCH = "/search";
const PARAM_SEARCH = "query=";
const DEFAULT_QUERY = "redux";
//const url = `${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${DEFAULT_QUERY}`;
//console.log(url);
class App extends Component {
constructor() {
super();
this.state = {
result: null
};
this.hitStories = this.hitStories.bind(this);
}
// handling the local state value
hitStories(result) {
this.setState({
result
});
}
// lifecycle method
// Note: componenetDidMount runs after the render method
componentDidMount() {
fetch(`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${DEFAULT_QUERY}`)
.then((response) => response.json())
.then((json_result) => this.hitStories(json_result))
.catch((error) => error);
}
render() {
console.log(this.state)
const { result } = this.state;
if (!result) {
return null;
}
return (
<div>
<h2>Fetch API in React</h2>
{result.map((
item
) => (
<div>
{item.title}
</div>
))}
</div>
);
}
}
export default App;
.map is used on an array, your result is not an array but an object. Try this:
render() {
const { result } = this.state;
return result ? (
<div>
<h2>Fetch API in React</h2>
{ Object.values(result).map((item) => (
<div>{item.title}</div>
))
}
</div>
): null;
}

Conditional within a render in the content display component in React.js

I have a component that needs to display the details of a movie according to the id that is passed in the URL (parameter). I'm having difficulty doing the conditional on the RENDER method. It's probably quite simple, but I'm still not very familiar with the React flow. Can you give me an idea?
Ex: Codesandbox
import React, { Component } from "react";
import api from "../../services/api";
export default class Movie extends Component {
state = {
movies: [],
movieId: {}
};
async componentDidMount() {
const { id } = this.props.match.params;
const response = await api.get("");
const currentParams = this.props.match.params;
this.setState({
movies: response.data,
movieId: `${id}`
});
console.log(this.state.movies);
console.log(this.state.movieId);
}
render() {
const movies = this.state.movies,
currentParams = this.state.movieId;
return (
<div className="movie-info">
{this.state.movies.map(movie => (
if( movie.event.id === currentParams ) {
<h1 key={movie.event.id}>{movie.event.title}</h1>
}
))}
</div>
);
}
}
You might not want to use map in this case since you only want to render one movie. You could instead use the find method and render that single movie if it's found.
class Movie extends Component {
// ...
render() {
const { movies, movieId } = this.state;
const movie = movies.find(movie => movie.event.id === movieId);
return (
<div className="movie-info">
{movie ? <h1 key={movie.event.id}>{movie.event.title}</h1> : null}
</div>
);
}
}

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.

how to pass props down using map

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>
);
}

Resources