display one image at a time from fetched data from json - javascript

I am a beginner in React trying to display one image at a time. Currently using this api https://salty-cove-08526.herokuapp.com/api/countries?format=json which sends 3 images at once. I am using axios to get the images and using map {this.state.countries.map(country => <img src={country.photo}/>)}
but this command in div img-wrapper displays all the 3 at once plz hlep
reactjs
class form extends Component{
constructor(props){
super(props);
this.state={
answer:'',
countries:[]
}
this.handleChange=this.handleChange.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
componentDidMount(){
axios.get('https://salty-cove-08526.herokuapp.com/api/countries?format=json')
.then(res=>{
this.setState({ countries:res.data});
})
}
}
render(){
return (
<div>
<section className="login">
<div className="loginContainer">
<div className="heading">
Guess the countries
</div>
<div className="img-wrapper">
{this.state.countries.map(country =>
<img src={country.photo}/>
)}
</div>
json
[
{
"id": 6,
"name": "canada",
"photo": "https://en.wikipedia.org/wiki/India#/media/File:Flag_of_India.svg",
"fact": "sdsds",
"capital": "sdsdsd",
"hint_1": "sdsd",
"hint_2": "sdsdsd"
},
{
"id": 2,
"name": "usa",
"photo": "https://en.wikipedia.org/wiki/India#/media/File:Flag_of_India.svg",
"fact": "ddc",
"capital": "new york",
"hint_1": "kuch bhi",
"hint_2": "kljn;kj"
},
{
"id": 3,
"name": "china",
"photo": "https://en.wikipedia.org/wiki/India#/media/File:Flag_of_India.svg",
"fact": "ddfdf",
"capital": "k k",
"hint_1": "jnjn",
"hint_2": "jknkjn"
}
]

You need to have something to determine which image you want to display. In the example below, I hold, in state, the index of the current image, and then only display the image at that index:
const images = [
{
"id": 6,
"name": "canada",
"photo": "https://en.wikipedia.org/wiki/India#/media/File:Flag_of_India.svg",
"fact": "sdsds",
"capital": "sdsdsd",
"hint_1": "sdsd",
"hint_2": "sdsdsd"
},
{
"id": 2,
"name": "usa",
"photo": "https://en.wikipedia.org/wiki/India#/media/File:Flag_of_India.svg",
"fact": "ddc",
"capital": "new york",
"hint_1": "kuch bhi",
"hint_2": "kljn;kj"
},
{
"id": 3,
"name": "china",
"photo": "https://en.wikipedia.org/wiki/India#/media/File:Flag_of_India.svg",
"fact": "ddfdf",
"capital": "k k",
"hint_1": "jnjn",
"hint_2": "jknkjn"
}
];
const PhotoDisplay = () => {
const [currentImageIndex, setCurrentImageIndex] = React.useState(0);
const handleNextClick = () => {
setCurrentImageIndex(currentImageIndex + 1);
};
const currentImage = images[currentImageIndex];
console.log(currentImage);
return <div>
<button onClick={handleNextClick}>Next Image</button>
<img src={currentImage.photo} />
</div>
}
ReactDOM.render(
<PhotoDisplay />,
document.getElementById('root')
)
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="root"></div>

Related

React table from object with objects

I got 2 types of json API and i want to display them in table. First one has following structure:
data1:[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere#april.biz",
"address":"Gwenborough",
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": "Romaguera-Crona"
},
{
"id": 2,
"name": "Ervin Howell",
"username": "Antonette",
"email": "Shanna#melissa.tv",
"address": "Wisokyburgh",
"phone": "010-692-6593 x09125",
"website": "anastasia.net",
"company": "Deckow-Crist"
}
]
Second:
data2:[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere#april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
},
{
"id": 2,
"name": "Ervin Howell",
"username": "Antonette",
"email": "Shanna#melissa.tv",
"address": {
"street": "Victor Plains",
"suite": "Suite 879",
"city": "Wisokyburgh",
"zipcode": "90566-7771",
"geo": {
"lat": "-43.9509",
"lng": "-34.4618"
}
},
}
]
My Table component works for first type of data (data1) and creates a table. But obviously for second (data2) type i'm getting error. I tried a lot of things and i can't get access to address and geo fields and can't display them in table.
Table component:
export default class Table extends React.Component {
constructor(props){
super(props);
this.getHeader = this.getHeader.bind(this);
this.getRowsData = this.getRowsData.bind(this);
this.getKeys = this.getKeys.bind(this);
}
getKeys = function(){
return Object.keys(this.props.data[0]);
}
getHeader = function(){
var keys = this.getKeys();
return keys.map((key, index)=>{
return <th key={key}>{key.toUpperCase()}</th>
})
}
getRowsData = function(){
var items = this.props.data;
var keys = this.getKeys();
return items.map((row, index)=>{
return <tr key={index}><RenderRow key={index} data={row} keys={keys}/></tr>
})
}
render() {
console.log('Get keys:', this.getKeys());
return (
<div>
<table>
<thead>
<tr>{this.getHeader()}</tr>
</thead>
<tbody>
{this.getRowsData()}
</tbody>
</table>
</div>
);
}
}
const RenderRow = (props) =>{
return props.keys.map((key, index)=>{
return <td key={props.data[key]}>{props.data[key]}</td>
})
}
const uniqueArr = [...data1, ...data2]
const formatData = uniqueArr.map((item) => {
if(typeof item.address === "object"){
return {
...item,
address: item.address.street.concat(", ", item.address.city),
company: item.company ? item.company.name : ""
}
}
return item
})

React Context Api with Json

I have nested json and arrays that are located in there. So the thing I am trying to do is this. I want to make a Search functionality, that 'functionality' would go through the arrays and based on a specific Id it would display the name of that specific object in the array. I have tried with Context api to share the state globally, I know its not the cleanest way of doing it, anyway it is giving me an error in FreeToPlayComponent ".filter is not a function".
Context
import React, { useState, useContext } from 'react';
export const SearchContext =React.createContext(null)
export default function SearchProvider({children}) {
const [searchValue, setSearchValue] = React.useState("");
function filterProduct(product) {
return product.name.toLowerCase().includes(searchValue.toLowerCase());
}
return(
<SearchContext.Provider value ={{filterProduct, searchValue, setSearchValue}}>
{children}
</SearchContext.Provider>
); }
json
[
{
"freetoplay": [{
"id": "0",
"image": "src=fsdf",
"price": "60$",
"name": "CS Go"
},
{
"id": "1",
"image": "src=fsdf",
"price": "6$",
"name": "Fifa"
}
],
"action": [{
"id": "2",
"image": "src=fsdf",
"price": "60$",
"name": "doom"
},
{
"id": "3",
"image": "src=fsdf",
"price": "66$",
"name": "cyberpunk"
}
],
"adventure": [
{
"id": "4",
"image": "src=fsdf",
"price": "60$",
"name": "indiana "
},
{
"id": "5",
"image": "src=fsdf",
"price": "43$",
"name": "torchlight"
}
]
}
]
Search Component
import React from 'react'
import './Search.css'
import { SearchContext } from './SearchContext';
function Search() {
const {searchValue, setSearchValue}=React.useContext(SearchContext);
return (
<div className='search'>
<form className="search__Form">
<input className="search__Input" type="text"
value ={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
type='text'
placeholder='Search '/>
</form>
</div>
)
}
export default Search
import React from 'react'
import Header from './Header'
import './App.css';
import SlideShow from './SlideShow';
import Routes from './Routes';
import data from "./data.json";
import SearchProvider from "./SearchContext";
function App() {
return (
<div className="app">
<SearchProvider>
<Header />
<SlideShow />
<Routes />
</SearchProvider>
</div>
);
}
export default App;
import React from 'react'
import data from "./data.json";
import {
Link
} from "react-router-dom";
import { SearchContext } from './SearchContext';
function FreeToPlay() {
const {filterProduct}=React.useContext(SearchContext);
return (
<>
<div className='All' >
{data[0].filter(filterProduct).freetoplay.map((product) => {
return (
<div className='f2p' key={product.id}>
<img src={product.image}></img>
<h2>{product.name}</h2>
<h5>{product.price}</h5>
<Link
to={`/payment/${product.id}`}
className='link'
>
Buy Now
</Link>
</div>
);
})}
</div>
</>
);
}
export default FreeToPlay
Your JSON data appears to be invalid, it has an extraneous opening curly bracket before the "action" key.
json
[
{
"freetoplay": [{
"id": "0",
"image": "src=fsdf",
"price": "60$",
"name": "CS Go"
},
{
"id": "1",
"image": "src=fsdf",
"price": "6$",
"name": "Fifa"
}
],
{ // <-- remove this!!
"action": [{
"id": "2",
"image": "src=fsdf",
"price": "60$",
"name": "doom"
},
{
"id": "3",
"image": "src=fsdf",
"price": "66$",
"name": "cyberpunk"
}
],
"adventure": [
{
"id": "4",
"image": "src=fsdf",
"price": "60$",
"name": "indiana "
},
{
"id": "5",
"image": "src=fsdf",
"price": "43$",
"name": "torchlight"
}
]
}
]
Also, based on the data shape and what your filterProduct function does
function filterProduct(product) {
return product.name.toLowerCase().includes(searchValue.toLowerCase());
}
it seems you should also be filtering the category/product array versus the outer array of categories/products since the category/product elements have the "name" property.
Change
data[0].filter(filterProduct).freetoplay.map
to
data[0].freetoplay.filter(filterProduct).map

I can not get data from this.state

I receive JSON from my back end, I save it in my state and I want to use it in props in another react component, but it doesn't work.
I try to show need date like that in props of my component - {this.state.movies["0"]["title"]}, but it doesn't work.
constructor() {
super();
this.state = {
movies: []
}
}
componentDidMount() {
this.getAllMoviesForMainPage();
}
getAllMoviesForMainPage() {
axios.get("http://localhost:8080/showAll")
.then(response => {
this.setState({ movies: response.data })
})
}
render() {
return (
<div className="qwerty">
<MainPageComponent />
<div className='moviePreviewGrid'>
<Router>
<div className="moviePreviewGrid-row">
<div className="moviePreviewGrid-col">
<MoviePreview
Title={this.state.movies["2"]["title"]}
MoviePreviewAvatar={DrivePoster}
SeeMore="unrelated long string here"
/>
<NavLink to="/showByTitle/Драйв">
<button type="button" className="myBtn">See more</button>
</NavLink>
</div>
and structure of my JSON
[
{
"id": 1,
"title": "Джокер",
"releaseDate": "2019",
"genre": "Триллер, драма, криминал",
"duration": "122 минуты",
"rating": 8.7,
"criticReviews": [
{
"criticName": "Anton",
"review": "anton review"
},
{
"criticName": "OldCritic",
"review": "old review"
}
],
"userReviews": [
{
"nickName": "Igor",
"review": "igor review"
},
{
"nickName": "Nik",
"review": "nik review"
}
]
},
{
"id": 2,
"title": "Ирландец",
"releaseDate": "2019",
"genre": "Драма, триллер, криминал, биографический",
"duration": "209 минут",
"rating": 8.4,
"criticReviews": [
{
"criticName": "YoungCritic",
"review": "young review"
}
],
"userReviews": [
{
"nickName": "Gambit",
"review": "gambit review"
},
{
"nickName": "Andrew",
"review": "andrew review"
}
]
},
{
"id": 3,
"title": "Драйв",
"releaseDate": "2011",
"genre": "Боевик, драма",
"duration": "100 минут",
"rating": 7.8,
"criticReviews": [
{
"criticName": "Critic",
"review": "review"
}
],
"userReviews": [
{
"nickName": "Anton",
"review": "anton review"
}
]
},
{
"id": 4,
"title": "Последний человек на Земле",
"releaseDate": "2015",
"genre": "Комедия",
"duration": "22 минуты",
"rating": 7.3,
"criticReviews": [
{
"criticName": "NewCritic",
"review": "new review"
}
],
"userReviews": [
{
"nickName": "Atomf7",
"review": "atomf7 review"
}
]
},
{
"id": 5,
"title": "Интерстеллар",
"releaseDate": "2014",
"genre": "Фантастика, драма, приключения",
"duration": "169 минут",
"rating": 8.6,
"criticReviews": [
{
"criticName": "Nik",
"review": "nik review"
}
],
"userReviews": [
{
"nickName": "Alice",
"review": "alice review"
}
]
}
]
and i wont to have for example title of first movie
In the first init, the this.state.movies has a length of 0 so this.state.movies["2"]["title"] of course would have no value at all
because getAllMoviesForMainPage is async (axios call) and takes a little longer to complete, so first you must give it an initial value and only when the request completes you can give it the real value.
example:
<MoviePreview
Title={this.state.movies.length > 0 ? this.state.movies[2].title : ""}
MoviePreviewAvatar={DrivePoster}
/>
Usually a state, isLoading is used for this case. So you can know when you received your data.
In the first render movies are not already fetched from the api.
So you need to conditionally render it.
import React, { Component } from "react";
import axios from "axios";
export default class Test extends Component {
constructor() {
super();
this.state = {
movies: [],
loading: true
}
}
componentDidMount() {
this.getAllMoviesForMainPage();
}
getAllMoviesForMainPage() {
axios.get("http://localhost:8080/showAll")
.then(response => {
this.setState({ movies: response.data, loading: false })
})
}
render() {
const { loading, movies } = this.state;
if (loading) {
return <div>Loading...</div>;
} else {
return (
<div>
{movies.length > 0 ? (
<div>First movie title: {movies[0].title}</div>
) : (
<div>No movies</div>
)}
</div>
);
}
}
}
You can check this example using a fake api.
You are making a GET request in componentDidMount which is async so until the promise is resolve in .then(.. your state does not contain response.data in movies.
The important thing to remember is component gets re-render every time you do this.setState(.. , so before you do setState in your getAllMoviesForMainPage method, the initial render will happen and it will contain an empty array in this.state.movies that you have defined in constructor
Also since your response contains array of objects, you would be using movies['2'].title instead of movies['2']['title']
So your render method should contain something like this to show movie preview:
<div className="moviePreviewGrid-col">
{this.state.movies.length ? (
<MoviePreview
Title={this.state.movies['2'].title}
MoviePreviewAvatar={DrivePoster}
SeeMore="unrelated long string here"
/>
) : (
<PlaceHolderPreview />
)}
<NavLink to="/showByTitle/Драйв">
<button type="button" className="myBtn">
See more
</button>
</NavLink>
</div>
PlaceHolderPreview can be your another component that will show -- well a placeholder for preview.
Hope it all makes sense.

React - Rendering an array of objects using Map

I'm trying to render an array of objects using Map and so far I've only been able to render the first item to the browser.
I figured something's up with my .map function, but I don't know enough about React and JS to pinpoint the problem.
Here's my App.js file:
// import stuff is here
class App extends Component {
constructor(props) {
super(props);
this.state = {
items: []
};
this.componentWillMount = this.componentWillMount.bind(this);
}
componentWillMount() {
fetch('THE-JSON-URL-IS-HERE')
.then(res => res.json())
.then(data => {
this.setState({ items: data });
});
render() {
const { items } = this.state;
return (
<div className="App">
{ items.map((item, num) => {
return (
<div className="people">
<div className="elem">
<p key={num}>{item.elems}</p>
</div>
<p key={num}><strong>{item.name}</strong></p>
<p key={num}><small>{item.title}</small></p>
<div className="hidden">
<p key={num}><small>{item.email}</small></p>
<p key={num}><small><strong>Office: </strong>{item.office}</small></p>
</div>
{/* <p>{item.manager}</p> */}
</div>
);
})}
</div>
);
}
}
export default App;
And here's a sample of the JSON file:
[
{
"elems": "Pr",
"name": "Abby Langdale",
"title": "President",
"email": "alangdale0#hubpages.com",
"office": "Javanrud",
"manager": [
{
"elems": "Vp",
"name": "Johnnie Mouncey",
"title": "Vice President",
"email": "jmouncey0#cnet.com",
"office": "Canto",
"manager": [
{
"elems": "Vp",
"name": "Concordia Burgwyn",
"title": "VP Quality Control",
"email": "cburgwyn0#dyndns.org",
"office": "Zhoukou",
"manager": [
{
"elems": "En",
"name": "Prissie Sainsberry",
"title": "Web Developer IV",
"email": "psainsberry0#yellowbook.com",
"office": "Tugu",
"manager": null
},
etc. Abby's info is all that I've rendered.
Since you're nesting arrays and objects into your first array element, the length of items is 1 and the only element is the Abby element with the rest of the data nested inside of it. To map through all of the elements, items should look like this array:
[
{
"elems": "Pr",
"name": "Abby Langdale",
"title": "President",
"email": "alangdale0#hubpages.com",
"office": "Javanrud",
"manager": ""
},
{
"elems": "Vp",
"name": "Johnnie Mouncey",
"title": "Vice President",
"email": "jmouncey0#cnet.com",
"office": "Canto",
"manager": ""
},
{
"elems": "Vp",
"name": "Concordia Burgwyn",
"title": "VP Quality Control",
"email": "cburgwyn0#dyndns.org",
"office": "Zhoukou",
"manager": ""
},
{
"elems": "En",
"name": "Prissie Sainsberry",
"title": "Web Developer IV",
"email": "psainsberry0#yellowbook.com",
"office": "Tugu",
"manager": null
}
]
If you need to maintain the relationship of managers, you can add an id to each object and reference it from another object.
[
{
"elems": "Pr",
"name": "Abby Langdale",
"title": "President",
"email": "alangdale0#hubpages.com",
"office": "Javanrud",
"manager": "",
"id" : 1
},
{
"elems": "Vp",
"name": "Johnnie Mouncey",
"title": "Vice President",
"email": "jmouncey0#cnet.com",
"office": "Canto",
"manager": 1
},
...
]
You would need a filter helper function to do the correct lookup for a manager's name but it should work.
Try flattening the array first. You would need to know the maximum number of levels that the array will have. Once it's flattened, you can use your map function:
const flatItems = items.flat(3); // flatten up to 3 levels
items.map((item, num) => {
return ( <render your div> );
}

Using angular to extract specific Json data

Can someone please point out where I am making a mistake.
Its a very simple application that is meant to print out the "name" field in and array of Json objects, Which is done via the line :
{{ctrl.contact[0].results[0].name.first}} or
{{ctrl.contact[1].results[0].name.first}}
(which in itself seems very convoluted)
I cannot get it to print out the name of each Json block individually by loop and here is what i have tried :
<div ng-repeat="i in ctrl.contact">
<span>{{ctrl.contact[i].results[0].name.first}}</span>
</div>
Im confident after spending a few hours tweaking and editing that my angular set up (app, controller etc) is fine.
code snippet below :
<html ng-app="ContactAppApp">
<head>
<title>My Contact App</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
</head>
<body>
<div>
<div ng-controller="ContactAppController as ctrl">
<h1>{{ctrl.test}}</h1>
<div ng-repeat="i in ctrl.contact">
<span>{{ctrl.contact[0].results[0].name.first}}</span>
</div>
</div>
</div>
</body>
<script>
var app = angular.module("ContactAppApp", [])
app.controller("ContactAppController", ContactAppController);
function ContactAppController() {
this.test = "This text is generated by Angular";
this.contact = [
{
"results": [
{
"gender": "male",
"name": {
"title": "mr",
"first": "tony",
"last": "cruz"
},
"location": {
"street": "9813 north road",
"city": "edinburgh",
"state": "humberside",
"postcode": "E84 4YD"
}
}
]
},
{
"results": [
{
"gender": "male",
"name": {
"title": "mr",
"first": "Jack",
"last": "cruz"
},
"location": {
"street": "9813 north road",
"city": "edinburgh",
"state": "humberside",
"postcode": "E84 4YD"
}
}
]
}
]
}
</script>
</html>
Try the following:
<div ng-repeat="i in ctrl.contact">
<span>{{i.results[0].name.first}}</span>
</div>
I would set up your array a little differently. Try something like this:
this.contact = {
"results": [
{
"gender": "male",
"name": {
"title": "mr",
"first": "tony",
"last": "cruz"
},
"location": {
"street": "9813 north road",
"city": "edinburgh",
"state": "humberside",
"postcode": "E84 4YD"
}
},
{
"gender": "male",
"name": {
"title": "mr",
"first": "Jack",
"last": "cruz"
},
"location": {
"street": "9813 north road",
"city": "edinburgh",
"state": "humberside",
"postcode": "E84 4YD"
}
}
]
}
Then in your ng-repeat, try something like this:
<div ng-repeat="item in contact.results">
<span>{{item.name.first}} {{$index}}</span>
</div>
If you are trying to track the index of the item in array, use $index, not i.

Categories