Related
// JSON File
{
"project": [
{
"id": "0",
"title": "Old Portfolio",
"images" :{
"main": "portfolio.png",
"second": ""
},
"content": ["This is one of my first few projects I made as a beginner", "At this project, I learned using JavaScript for making interactive elements like a navbar button. This project was not really something I'm proud of. Hence why I'm making a new portfolio but now with react"]
,
"tags": ["HTML5", "CSS", "JavaScript", "jQuery"]
},
{
"id": "1",
"title": "Twitter Clone",
"images" :{
"main": "twitter_clone.png",
"second": ""
},
"content": ["Project I made to improve my skills in PHP and MySQL.", "At this project, I used MySQL to store data and use PHP to alter what my website will show to the user. I've also used AJAX and JQuery for processing data from MySQL with PHP."]
,
"tags": ["HTML5", "CSS", "JavaScript", "PHP", "MySQL", "jQuery", "AJAX"]
}
]
}
// projectList is from a JSON file
// ProjectList.js
{projectList.map((project) => (
<Projects key={project.id} projectData={project}/>
))}
// Projects.js
const imagePath = "../images/";
const mainImage = imagePath + projectData.images.main
const Projects = ({projectData}) => {
<img style={{
width: "100%",
}} src={mainImage}alt="" />
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I have a JSON file that stores the images. This is gonna be for a list of projects.
The image src is not working and I can't import an image inside the function.
I hope someone could help I am new to React
JSON should not be object, I guess in this case you can use array.
instead of using "img" you must use thumbnail, cause your object(project) has no "img" key, but has "thumbnail"->
const mainImage = imagePath + projectData.thumbnail.main
// JSON File
[
{
"id": "0",
"title": "Old Portfolio",
"thumbnail" :{
"main": "portfolio.png",
"second": ""
},
"content": ["This is one of my first few project I made as a beginner", "At this project I learned using JavaScript for making interactive elements like a navbar button. This project was not really something I'm proud of. Hence why I'm making a new portfolion but now with react"]
,
"tags": ["HTML5", "CSS", "JavaScript", "jQuery"]
},
{
"id": "1",
"title": "Twitter Clone",
"thumbnail" :{
"main": "twitter_clone.png",
"second": ""
},
"content": ["Project I made to improve my skills in PHP and MySQL.", "At this project I used MySQL to store data and use PHP to alter what my website will show to the user. I've also used AJAX and JQuery for processing data from MySQL with PHP."]
,
"tags": ["HTML5", "CSS", "JavaScript", "PHP", "MySQL", "jQuery", "AJAX"]
}
]
// projectList is from a JSON file
// ProjectList.js
{projectList.map((project) => (
<Projects key={project.id} projectData={project}/>
))}
// Projects.js
const imagePath = "../images/";
const mainImage = imagePath + projectData.thumbnail.main
const Projects = ({projectData}) => {
<img style={{
width: "100%",
}} src={mainImage}alt="" />
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I finally found a way,
I put the images on the public folder "public/images/image.png"
and
const Projects = ({projectData}) => {
<img src={`images/${projectData.images.main}`}/>
}
I fetch an api on componentDIdMount() then store the json to a state then I pass that state as a prop, I have no problem showing the data except on arrays.
<Component details={this.state.details} />
json:
{
"adult": false,
"backdrop_path": "/qonBhlm0UjuKX2sH7e73pnG0454.jpg",
"belongs_to_collection": null,
"budget": 90000000,
"genres": [
{
"id": 28,
"name": "Action"
},
{
"id": 878,
"name": "Science Fiction"
},
{
"id": 35,
"name": "Comedy"
},
{
"id": 10751,
"name": "Family"
}
]
}
then I try to map the genres:
<div className={style.genre}>
{details.genres.map(g => (
<span key={g.id}>{g.name}</span>
))}
</div>
But then I get Cannot read property 'map' of undefined, I don't know why this is happening because I'm able to do details.budget
It's trying to read data before you get the result from api.
so write the map function as
{details&&details.genres&&details.genres.map(g => (
<span key={g.id}>{g.name}</span>
))}
In react Initially when component is mounted, render() function is called and then componenentDidMount() is called in which you fetch data. So Initially details is empty. So you need to write the condition.
For some reason I'm unable to access the "question" key within the results array. Could someone help please? This is just a side project I've started and have been tearing my hair out for hours trying to get this first basic part to work. I've only been using react and API's for about a week now and I'm super inexperienced, so any help would be appreciated.
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
constructor() {
super()
this.state = {
questionList: []
}
}
componentDidMount() {
fetch('https://opentdb.com/api.php?amount=10')
.then(resp => resp.json())
.then(resp => this.setState({ questionList: resp }))
}
render() {
return (
<div>{this.state.questionList.results[0].question}</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
and here's the API data -
{
"response_code": 0,
"results": [
{
"category": "Entertainment: Film",
"type": "multiple",
"difficulty": "medium",
"question": "Which of the following James Bond villains is not affiliated with the SPECTRE organization?",
"correct_answer": "Auric Goldfinger",
"incorrect_answers": [
"Dr. Julius No",
"Rosa Klebb",
"Emilio Largo"
]
},
{
"category": "Geography",
"type": "multiple",
"difficulty": "hard",
"question": "The mountainous Khyber Pass connects which of the two following countries?",
"correct_answer": "Afghanistan and Pakistan",
"incorrect_answers": [
"India and Nepal",
"Pakistan and India",
"Tajikistan and Kyrgyzstan"
]
},
{
"category": "Entertainment: Video Games",
"type": "multiple",
"difficulty": "medium",
"question": "In Team Fortress 2, which class wields a shotgun?",
"correct_answer": "Everyone Listed",
"incorrect_answers": [
"Heavy",
"Soldier",
"Engineer"
]
},
{
"category": "Entertainment: Video Games",
"type": "multiple",
"difficulty": "easy",
"question": "Who is the leader of Team Mystic in Pokémon Go?",
"correct_answer": "Blanche",
"incorrect_answers": [
"Candela",
"Spark",
"Willow"
]
},
{
"category": "Science & Nature",
"type": "multiple",
"difficulty": "easy",
"question": "The medical term for the belly button is which of the following?",
"correct_answer": "Umbilicus",
"incorrect_answers": [
"Nevus",
"Nares",
"Paxillus"
]
},
{
"category": "Entertainment: Cartoon & Animations",
"type": "multiple",
"difficulty": "easy",
"question": "What is lost in Hawaiian and is also the name of a little girl in a 2002 film which features a alien named "Stitch"?",
"correct_answer": "Lilo",
"incorrect_answers": [
"Lolo",
"Lucy",
"Lulu"
]
},
{
"category": "Entertainment: Cartoon & Animations",
"type": "multiple",
"difficulty": "hard",
"question": "In "Gravity Falls", what does Quentin Trembley do when he is driven out from the White House?",
"correct_answer": "Eat a salamander and jump out the window.",
"incorrect_answers": [
"Leave in peace.",
"Jump out the window.",
"Release 1,000 captive salamanders into the white house."
]
},
{
"category": "Entertainment: Television",
"type": "multiple",
"difficulty": "hard",
"question": "Who was the winner of "Big Brother" Season 10?",
"correct_answer": "Dan Gheesling",
"incorrect_answers": [
"Bryce Kranyik",
"Ryan Sutfin",
"Chris Mundorf"
]
},
{
"category": "General Knowledge",
"type": "multiple",
"difficulty": "easy",
"question": "Terry Gilliam was an animator that worked with which British comedy group?",
"correct_answer": "Monty Python",
"incorrect_answers": [
"The Goodies",
"The League of Gentlemen",
"The Penny Dreadfuls"
]
},
{
"category": "Entertainment: Video Games",
"type": "multiple",
"difficulty": "easy",
"question": "In Counter-Strike: Global Offensive, what's the rarity of discontinued skins called?",
"correct_answer": "Contraband",
"incorrect_answers": [
"Discontinued",
"Diminshed",
"Limited"
]
}
]
}
Thanks!
This will surely fail, since you are calling an asynchronous action, but your render relies on that explicitly:
{this.state.questionList.results[0].question}
You are probably receiving Cannot read property 'question' of undefined
or
Cannot read property '0' of undefined
The most basic solution would be to check if the questionList actually has some data inside.
Note: questionList in an array, not an object.
render() {
if (this.state.questionList.length === 0) {
return null;
}
return (
<div>{this.state.questionList[0].results[0].question}</div>
);
}
However the best, but the longest solution would be check step-by-step that questionList has a correct structure:
{this.state.questionList[0]
&& this.state.questionList.results
&& this.state.questionList.results[0]
&& this.state.questionList.results[0].question}
As other's have noted, your API call will take a period of time, and your App will render before it is done, so your data isn't there yet when it goes to render. You're basically trying to get data that doesn't exist yet.
I like to have a loading flag on my state to show loading stuff, as well an an error flag for any errors that come in.
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
constructor() {
super()
this.state = {
questionList: {
isLoading: true,
error: null,
data: null,
}
}
}
componentDidMount() {
fetch('https://opentdb.com/api.php?amount=10')
.then(resp => resp.json())
.then(resp => this.setState(
{questionList:
{data: resp, isLoading: false, error: null}
}))
.catch(e => this.setState({questionList: {data: null, error: e, data: null}}))
}
render() {
if (this.state.questionList.isLoading)
return <Loading />
if (this.state.questionList.error)
return <Error error={this.state.questionList.error} />
return (
<div>{this.state.questionList.data.results[0].question}</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
You can and should be a little smarter with your checks, and data fixing, etc, etc... but that is the gist of how I deal with it.
I also recommend wrapping up your API calls in a module. So you could say api.questions.getList().then(...) instead of having the fetch in your components, and any data conversions, or other ugly stuff can be put in those modules. It isn't really related to your question (and would probably be overkill for this anyways), but since you seem to new to react I'll throw that out there for you.
use
console.log in render()
and you will see that your state is empty, because you call async function.
There is:
Api call - it can take 1 sec, 10 sec, 20 sec etc...
call render() - your state is empty because you need to wait for API response
you will get error...
You can add some code, eg:
render() {
if (this.state.questionList.length === 0) {
return '<div>Loading...</div>';
}
return (
<div>{this.state.questionList.results[0].question}</div>
)
}
I am not sure that your results are back to the component by the time it renders. I think you need to run a check to see if the results are there. Can you try something like this and we can go from here?
{this.state.questionList.results.length > 1 && this.state.questionList.results[0].question}
I'm attempting to incorporate video into a flat feed from GetStreamIO. My current approach is to embed a video element from Expo into the content body of the Activity UI component if the post has a video link. Starting with Youtube links only. I'm running into an issue where I'm not able to select the video url when it's available nested in props.activity.attachments. For some reason I cannot directly access the object in the videos array directly without converting the value to JSON. I referenced this StackOverflow Post for the JSON workaround.
My code to check if attachment has video url and grab it if it does
const LikeActivity = (props) => {
if (props.activity.attachments != undefined) {
console.log(props.activity.attachments)
console.log(fetchFromObject(props.activity.attachments, "og"))
var og = fetchFromObject(props.activity.attachments, "og")
var videos = fetchFromObject(og, "videos")
console.log(og)
// Can get the og object but cannot pull video url from it.
}
return (
<Activity
{...props}
Footer={
<View>
// For Now just putting this here to see the video element render. Need to pass URI from Post to element eventually.
<Video
source={{ uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4' }}
rate={1.0}
volume={1.0}
isMuted={false}
resizeMode="cover"
shouldPlay
isLooping
style={{ width: 300, height: 300 }}
/>
<LikeButton {...props} />
</View>
}
/>
);
};
My App implementation
<StreamApp
apiKey="XXXX"
appId="XXXX"
token="XXXXXX"
>
<FlatFeed
feedGroup="timeline"
userId="user-one"
Activity={LikeActivity}
/>
</StreamApp>
Fetch From Object method
function fetchFromObject(obj, prop) {
if(typeof obj === 'undefined') {
return false;
}
var _index = prop.indexOf('.')
if(_index > -1) {
return fetchFromObject(obj[prop.substring(0, _index)], prop.substr(_index + 1));
}
return obj[prop];
}
The feed consists of a number of posts and the props.activity.attachments has the following values at runtime. Each post with a link currently has a rich snippet. The attachments value also recognizes videos vs images. I've also included an image of the feed here as a reference.
Object {
"og": Object {
"description": "Why choose one when you can wear both? These energizing pairings stand out from the crowd",
"images": Array [
Object {
"image": "https://www.rollingstone.com/wp-content/uploads/2018/08/GettyImages-1020376858.jpg",
},
],
"title": "'Queen' rapper rescheduling dates to 2019 after deciding to “reevaluate elements of production on the 'NickiHndrxx Tour'",
"url": "https://www.rollingstone.com/music/music-news/nicki-minaj-cancels-north-american-tour-with-future-714315/",
},
}
undefined
Object {
"og": Object {
"description": "Why choose one when you can wear both? These energizing pairings stand out from the crowd",
"images": Array [
Object {
"image": "https://images.wsj.net/im-21927/TOP",
},
],
"title": "How to Pair Neutrals and Bright Colors",
"url": "https://graphics.wsj.com/glider/marketreport-4a039902-7e0d-4631-ab83-6cc1931c1bc6",
},
}
undefined
Object {
"og": Object {
"description": "Serial entrepreneur Elon Musk wants to fundamentally change the way we live. But his path to success has been characterized by both great accomplishments and flirtations with failure.",
"images": Array [
Object {
"image": "https://static01.nyt.com/images/2018/08/22/us/19xp-musk-vid-2/19xp-musk-vid-2-videoSixteenByNine1050.jpg",
},
],
"title": "Elon Musk’s Highs and Lows: PayPal, SpaceX, Tesla",
"url": "https://www.nytimes.com/video/business/100000006060092/elon-musk-tesla-spacex.html",
},
}
undefined
Object {
"og": Object {
"description": "We are in a Simulation - Elon Musk",
"images": Array [],
"site_name": "YouTube",
"title": "We are in a Simulation - Elon Musk",
"type": "video.other",
"url": "https://www.youtube.com/watch?v=xBKRuI2zHp0",
"videos": Array [
Object {
"height": "360",
"secure_url": "https://www.youtube.com/embed/xBKRuI2zHp0",
"type": "text/html",
"width": "640",
},
],
},
}
Array [
Object {
"height": "360",
"secure_url": "https://www.youtube.com/embed/xBKRuI2zHp0",
"type": "text/html",
"width": "640",
},
]
Object {
"images": Array [
"https://cdn.vox-cdn.com/thumbor/OBDFDT9j-nHEpGLckE4u5ibX2qU=/1400x1400/filters:format(png)/cdn.vox-cdn.com/uploads/chorus_asset/file/13589869/edu_distance_to_the_moon.png",
"https://www.jpl.nasa.gov/images/mars/20170622/PIA01466-16.jpg",
"http://cdn.sci-news.com/images/enlarge4/image_5608_2e-Jupiter.jpg",
"https://d2r55xnwy6nx47.cloudfront.net/uploads/2018/07/SolarFull_SeanDoran_2880FullwidthLede-2880x1620.jpg",
],
}
Something weird is going on:
This is my initial state (a .js file)
import moment from 'moment';
let date = moment();
var previousDate = moment("2015-12-25");
export const projects = [
{
"id": 0,
"metadata": {
"fields":
[{
"id": 1,
"order": 1,
"name": "Name",
"value": "Collection 1"
},
{
"id": 2,
"order": 2,
"name": "Created On",
"value": date
},
{
"id": 3,
"order": 3,
"name": "Last Modified On",
"value": previousDate
},
{
"id": 4,
"order": 4,
"name": "Status",
"value": "Filed"
}],
"tags":
[{
"id": 1,
"order": 1,
"value": "tag1"
},
{
"id": 2,
"order": 2,
"value": "tag2"
},
{
"id": 3,
"order": 3,
"value": "tag3"
},
{
"id": 4,
"order": 4,
"value": "tag4"
}]
}
}
This is ProjectsList.js:
import React from 'react';
import Project from './Project';
import { projects } from 'initialState';
export default (props) => {
return(
<div className="projectsList">
{projects.map(project => (
<article key={project.id}><Project fields={project.metadata.fields} /></article>
))}
</div>
)
}
And this one's Project.js:
import React from 'react';
export default (props) => {
return(
<ul className="fields">
{props.fields.map(field => <li key={field.id}>{field.name}</li>) }
</ul>
)
}
I am trying to render a bunch of projects in a list, and every project contains a bunch of metadata key-value pairs that it shows.
So basically, the wiring does not matter, it all works fine.
Except for this:
If you look up at the initial state file (first one up there), there is an array of multiple objects in fields. Each object shows 4 key-value pairs
id
order
name
value
Now, in Project.js, the line where I go
{props.fields.map(field => <li key={field.id}>{field.name}</li>) }
looks like I can switch the {field.name} for {field.id}, to show the id in text. Or I can go {field.order}, to display the order.
But weirdly enough, if I want to show the actual value of the field, like so {field.value}, it throws.
invariant.js?4599:38
Uncaught Invariant Violation: Objects are not valid as a React child (found: Mon Jun 20 2016 21:40:33 GMT-0400). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `StatelessComponent`.
I even went as far (sigh) as changing the string value in every fields to val, juste to make sure value wasn't some kind of a reserved word.
Still threw.
Anybody can help me understand what I have done wrong, here?
Thanks Guys.
You are assigning to variable values to the value property in your state file, which are most likely not strings, but objects:
export const projects = [{
"id": 0,
"metadata": {
"fields":
[
...
{
"id": 2,
"order": 2,
"name": "Created On",
"value": date // one
},
{
"id": 3,
"order": 3,
"name": "Last Modified On",
"value": previousDate // and another one
},
...
]
...
}
}
If typeof children returns "object" (and children is neither an array, nor a ReactElement), it throws:
https://github.com/facebook/react/blob/dc6fc8cc0726458a14f0544a30514af208d0098b/src/shared/utils/traverseAllChildren.js#L169
Here's a simplest example to demonstrate this:
const IllegalComponent = () => <span>{{}}</span>
You are supposed to supply a string (or number) so that React could inline that as the children in <li>. Children should be something that's renderable and implements ReactNode.
If the children is an object, React would not know how to render it. You should explicitly convert the value to String.
Try this to see if it works:
{props.fields.map(field => <li key={field.id}>{field.value.toString()}</li>) }