I apologise as this is probably either very basic or i've done something compeltely wrong. I'm brand new to React, and coding in general, and I'm trying to make a React app that shows the recipes im using on cards. The cards in turn should be searchable and dynamic, dissapearing if they don't match etc.
This is my app.js file, that when run, it just brings up my custom "Loading" screen without data. Where have I messed up on this?
import React, {Component} from 'react';
import CardList from './CardList';
import SearchBox from './SearchBox';
import Scroll from "./Scroll";
import "./App.css"
class App extends Component {
constructor() {
super()
this.state = {
recipes: [],
searchfield: "",
}
}
componentDidMount() {
fetch("./recipedata.json")
.then(response => { return response.json();})
.then(recipedata => {this.setState({recipes: recipedata})});
}
onSearchChange= (event) =>{
this.setState({searchfield: event.target.value})
}
render() {
const filteredRecipe = this.state.recipes.filter(recipes =>{
return recipes.name.toLowerCase().includes(this.state.searchfield.toLowerCase());
})
if (this.state.recipes.length === 0) {
return <h1 class="f1 tc">Loading</h1>
} else {
return(
<div className="tc">
<h1 className="f1">Recipes</h1>
<SearchBox searchChange={this.onSearchChange} />
<Scroll>
<CardList recipe={filteredRecipe}/>
</Scroll>
</div>
)
}
}
}
export default App
Thanks in advance
edit: I have been asked to post the contents of recipedata.json:
[
{
"id" : 1,
"name" : "Carrot cake",
"type" : "sweet",
"author" : "Grandma",
"link" : "recipes/carrotcake.html"
},
{
"id" : 2,
"name" : "Spicy chicken pitta filling",
"type" : "savoury",
"author" : "Grandma",
"link" : "recipes/chickenpitta.html"
},
{
"id" : 3,
"name" : "Mushroom ham and chicken crusty puff pies",
"type" : "savoury",
"author" : "Grandma",
"link" : "recipes/crustypuff.html"
},
{
"id" : 4,
"name" : "Sweet potato pumpkin seed rolls",
"type" : "savoury",
"author" : "Grandma",
"link" : "recipes/sweetpotrolls.html"
},
{
"id": 5,
"name": "Wild mushroom wafer",
"type": "savoury",
"author" : "Grandma",
"link": "recipes/mushroomwafer.html"
},
{
"id": 6,
"name": "Piri Piri chicken sauce",
"type": "savoury",
"author": "Grandma",
"link": "recipes/piriRecipe.html"
},
{
"id": 7,
"name": "Chicken Liver Pate'",
"type": "savoury",
"author": "Grandma",
"link": "recipes/pate.html"
},
{
"id": 8,
"name": "Creamy mushroom pasta",
"type": "savoury",
"author": "Grandma",
"link": "recipes/mushroompasta.html"
},
{
"id": 9,
"name": "Cheesey garlic bread",
"type": "savoury",
"author": "Grandma",
"link": "recipes/gbread.html"
},
{
"id": 10,
"name": "Mini quiches",
"type": "savoury",
"author": "Grandma",
"link": "recipes/miniquiche.html"
},
{
"id": 11,
"name": "Sticky lemon ginger cake",
"type": "sweet",
"author": "Grandma",
"link": "recipes/stickyrecipe.html"
},
{
"id": 12,
"name": "Sticky toffee pudding",
"type": "sweet",
"author": "Grandma",
"link": "recipes/stickytoffee.html"
},
{
"id": 12,
"name": "Iced cream buns",
"type": "sweet",
"author": "Grandma",
"link": "recipes/icedcreambuns.html"
},
{
"id": 13,
"name": "Pineapple Cake",
"type": "sweet",
"author": "Grandma",
"link": "recipes/pineapplecake.html"
}
]
Edit 2:
Thanks for your help all, I've now fixed the app.js file and the Json is being returned. I'm now faced with this error in my CardList.js component:
TypeError: Cannot read property 'map' of undefined
CardList
C:/Users/mattj/OneDrive/Desktop/coding/gmcb-react-app/src/CardList.js:5
2 | import Card from './Card.js';
3 |
4 | const CardList = ({recipes}) => {
> 5 | return <div>
6 | {recipes.map((recipedata, i) => {
7 | return(
8 | <Card
code:
import React from 'react';
import Card from './Card.js';
const CardList = ({recipes}) => {
return <div>
{recipes.map((recipedata, i) => {
return(
<Card
key={i}
id={recipes[i].id}
name={recipes[i].name} />
)
})}
</div>
}
export default CardList
What have I messed up here?
Regarding issue #2 you posted it is really tough to say, however I think you are overcomplicating things with your card list. You should simply pass an array of filtered recipes to your component.
Your card list component you should just pass an entire recipe option to the component instead of trying to pass specific props. If in the future you add more keys to each recipe object you wont have to adjust your card list
const CardList = ({recipes}) => {
return (
<div>
{
recipes.map(recipe => {
return <Card recipe={recipe} key={recipe.id} />
})
}
</div>
)
}
Inside your card component you can destructure the keys off the recipe object
const Card = ({recipe}) => {
return (
<div>
<h3>{recipe.name}</h3>
<p>{recipe.type} - {recipe.author}</p>
<hr />
</div>
)
}
I made you a code sandbox, I used React Hooks and a mockAxios call in order to fake what a server would do and so you have some code for if you want to call an API in the future.
https://codesandbox.io/s/broken-glitter-4wb61?file=/src/App.js
You don't need to use fetch to get the data from the local json file.
You can simply import the contents of ./recipedata.json by doing this:
import recipedata from './recipedata.json';
And then change your componentDidMount to this:
componentDidMount() {
this.setState({ recipes: recipedata });
}
You mostly use fetch when you are trying to fetch data from a http server. Read more here and here
To support #Qubaish Bhatti's comment, yes, there is no need to have recipes in state. You can use it directly and do away with this.state.recipes
Related
Hey I am a beginner in react trying to make my first full stack app, I am fetching data from mongodb using axios and storing data in fetchedjobs array. Jobtitle array only has the title property of the fetchedjobs and I want to print all the entries but not able to. For now I am printing these elements by hard coding the indexes {this.state.jobtitle[0]} .
Please Help
class FindJob extends Component{
constructor(props){
super(props);
this.state={
fetchedjobs:[],
jobtitle:[],
}
}
componentDidMount(){
axios.get(' http://localhost:4002/api/findjob')
.then(res=>{
this.setState({
fetchedjobs:res.data
})
let jobtitle=[]
this.state.fetchedjobs.map(fetchedjob=>
jobtitle.push(fetchedjob.jobtitle)
)
console.log(jobtitle[0])
this.setState({
jobtitle
})
})
}
render(){
return(
<div className="content">
<h5>{this.state.jobtitle[0]}</h5>
</div>
);
}
}
export default FindJob;
fetched json
[
{
"_id": "600469700459a40c088f3dde",
"jobtitle": "swe",
"company": "ibm",
"officelocation": "ggn",
"jobtype": "Part Time",
"publisher": "sid",
"date": "2021-01-17T16:44:32.084Z",
"__v": 0
},
{
"_id": "600469aa0459a40c088f3ddf",
"jobtitle": "janitor",
"company": "cisco",
"officelocation": "delhi",
"jobtype": "Full Time",
"publisher": "tanmya",
"date": "2021-01-17T16:45:30.218Z",
"__v": 0
},
{
"_id": "60046ae8b95ae81c14278f9e",
"jobtitle": "fljdk",
"company": "ndkf",
"officelocation": "mdfkfm",
"jobtype": "Part Time",
"publisher": "tanmya",
"date": "2021-01-17T16:50:48.311Z",
"__v": 0
}
]
You can create sync call in setState method and try it,
axios.get(' http://localhost:4002/api/findjob')
.then(res=>{
this.setState({ fetchedjobs:res.data }, () => {
let jobtitle=[]
this.state.fetchedjobs.map(fetchedjob=>
jobtitle.push(fetchedjob.jobtitle)
)
this.setState({ jobtitle})
})
})
Try this:
render(){
return(
<div className="content">
{this.state.jobtitle.length?this.state.jobtitle.map((item)=>{
return <h5>{item._id}</h5> //here you can display any property that you wish to
})
:null}
</div>
);
}
Just started using i18next and having a bit of issues translating the following data.
export const educationData = [
{ education: "Some education 1", timeframe: "2017 - 2018", id: 1 },
{ education: "Some education 2", timeframe: "2016 - 2017", id: 2 },
{ education: "Some education 3", timeframe: "2015 - 2016", id: 3 },
{ education: "Some education 4", timeframe: "2014 - 2015", id: 4 }
];
JSON in locales for different languages looks like:
"education": {
"heading": "Education",
"educationData": [
{
"id": 1,
"education": "Some education 1",
"timeframe": "2017 - 2018"
},
{
"id": 2,
"education": "Some education 2",
"timeframe": "2016 - 2017"
},
{
"id": 3,
"education": "Some education 3",
"timeframe": "2015 - 2016"
},
{
"id": 4,
"education": "Some education 4",
"timeframe": "2014 - 2015"
}
]
}
Component looks like:
import React from "react";
import { useTranslation } from "react-i18next";
import { educationData } from "../data/educationData";
import Education from "./Education.js";
function ListEducation() {
const { t } = useTranslation();
return (
<div className="education py-1">
<h2>{t("education.heading")}</h2>
<hr />
{educationData.map((edu) => (
<Education
key={edu.id}
education={edu.education}
timeframe={edu.timeframe}
/>
))}
</div>
);
}
export default ListEducation;
How do i get the translations to work in the .map() function? Outside of .map() something like t("education.educationData.0.education") works fine.
Inside .map function it just outputs "education.educationData.0.education" as a string.
You can get access to an array from file with translations using:
t('education.educationData', { returnObjects: true })
and then easily map through this array.
Source: i18next documentation: Arrays
You can try this
{t(`education.educationData.${id}.${education}`)}
You're basically concatenating the string.
I have json file named "Bread.json" following is the content of the file.
How to use image name dynamically in <Image>
I'm trying following but getting error. I'm getting image name's array from json file into the Flatlist, so {item.img} = my image name from json file. But not working!
<Image source={require('../images/'+{item.img})} />
So, how can I use image name in source of the <Image>, Also I can not use require() function into my json file. Any help?
"bread.json"
[
{
"id": "1",
"img": "1.jpg",
"cat": "Breakfast",
"title": "Small Semolina Griddle Breads"
},
{
"id": "2",
"img": "2.jpg",
"cat": "Side",
"title": "Corn Bread"
},
{
"id": "3",
"img": "3.jpg",
"cat": "Appetizer",
"title": "Fresh Tomato Bruschetta"
}
]
You can try this!
<Image source={getImageSource(item.img)} />
function getImageSource(image) {
let imageSrc = require('../images/logo.png');
switch (image) {
case "1.jpg":
imageSrc = require('../images/1.jpg');
break;
default:
break;
}
return imageSrc;
}
Hope this helps!
1) Create a file (to hold JSON data) e.g bread.js:
const Breads=[
{
"id": "1",
"img" : require('../images/1.jpg'),
"cat": "Breakfast",
"title": "Small Semolina Griddle Breads"
},
{
"id": "2",
"img" : require('../images/2.jpg'),
"cat": "Side",
"title": "Corn Bread"
},
{
"id": "3",
"img" : require('../images/3.jpg'),
"cat": "Appetizer",
"title": "Fresh Tomato Bruschetta"
}
]
export default Breads;
2) Then import the data in component and loop through the list using a FlatList
import Breads from './bread.js';
<FlatList
data={Breads}
keyExtractor={(item, index) => item.id}
renderItem={({item}) => <View>
<Image source={item.src} />
<Text>{item.title}</Text>
</View>
}
/>
I am still learning Vue.js. At the moment I am trying to make a simple filtered list method that pulls the data from a json file in Vue. I think that I am having trouble figuring out the correct syntax.
I just cant seem to get it right. Any help is more than welcome :)
This is Vue file:
<template>
<section>
<ul>
<li v-for="product in rings" :key="product">
{{product.title}}
</li>
</ul>
</section>
</template>
<script>
import data from '#/assets/data.json';
export default {
data() {
return {
products: []
}
},
methods: {
computed: {
rings(){
return this.products.filter(product => product.type == 'Ring')
}
}
}
}
</script>
And this is the Json file:
{ "products": [
{
"title": "Ring 1",
"description": "something",
"type": "Ring",
"year": "2018",
"image": "...",
"price": "2000,00 kr."
},
{
"title": "Halskæde 1",
"description": "something",
"type": "Halskæde",
"year": "2018",
"image": "...",
"price": "2000,00 kr."
},
{
"title": "Armbånd 1",
"description": "something",
"type": "Armbånd",
"year": "2018",
"image": "...",
"price": "2000,00 kr."
},
{
"title": "Ørering 1",
"description": "something",
"type": "Ørering",
"year": "2018",
"image": "...",
"price": "2000,00 kr."
}
]
}
You imported the data but never used anywhere inside the component:
import data from '#/assets/data.json';
// notice the data here is just a variable and it has nothing to do with the
// component's data property
export default {
data () {
return {
products: data.products // init products with imported data
}
},
Or with the destructuring syntax:
import { products } from '#/assets/data.json';
export default {
data () {
return {
products // init products with imported data
}
},
I'm newbie to Angular JS.
I am using Angular 2 in my project.
My JSON data is in below
"locations": [
{
"id": "ASS",
"name": "test center",
"city": "Staten Island",
"zip": "10301",
"state" : "texas"
},
{
"id": "ASD",
"name": "test center1",
"city": "Staten Island",
"zip": "10301",
"state" : "Florida"
},
{
"id": "AAY",
"name": "test center2",
"city": "Staten Island",
"zip": "10301",
"state" : "Florida"
},
{
{
"id": "ASD",
"name": "test center1",
"city": "Staten Island",
"zip": "10301",
"state" : "Florida"
}
],
I want to display data group by state.
texas : <div>ASS</div>
florida : <div>ASD</div>
<div>AAY</div>
<div>ASD</div>
group.pipe.ts:
#Pipe({name: 'groupBy'})
export class GroupByPipe implements PipeTransform {
transform(value: Array<any>, field: string): Array<any> {
console.log('test');
const groupedObj = value.reduce((prev, cur)=> {
if(!prev[cur[field]]) {
prev[cur[field]] = [cur];
} else {
prev[cur[field]].push(cur);
}
return prev;
}, {});
return Object.keys(groupedObj).map(key => ({ key, value: groupedObj[key]
}));
}
location.component.ts:
import {GroupByPipe} from '../group.pipe';
#NgModule({
declarations : [GroupByPipe]
})
My error :
Unhandled Promise rejection: Template parse errors:
The pipe 'groupBy' could not be found (" <div class="col-sm-12 left_otr">
<div class="col-md-6 col-sm-6 left" *ngFor="let [ERROR ->]item
of pagedItems | groupBy : 'state'">
How to solve this?
Just Passed the array and field to the below code:
transform(value: Array<any>, field: string): Array<any> {
const groupedObj = value.reduce((prev, cur)=> {
if(!prev[cur[field]]) {
prev[cur[field]] = [cur];
} else {
prev[cur[field]].push(cur);
}
return prev;
}, {});
return Object.keys(groupedObj).map(key => ({ key, value: groupedObj[key] }));
}
didn't used pipes.
updated my html as like below:
<div *ngFor="let item1 of pagedItems">
<h1>{{item1.key}}</h1>
<div *ngFor="let item of item1.value">
// my logic is here.
</div