REACT - How to display the text contained in an url - json

The question is not as easy as it sounds, but I couldn't find a way to cover it fully without probably confusing the readers
I have a json message stored in an url, which has an url field itself.
So it would look something like this:
{ "type": "text", "url": "http://pastebin.com/raw/1U5vhVzH" }
Inside that url, there is the content I want to display, which is in this case, simple text
With my code, I can already obtain the pastebin url, but now I can't seem to find a way to display it's content.
If it was an image, it would be easy since I could use <img src = {pastebinURL} to get what's inside that json field url, How can I replicate the same behaviour for the text?
Here's my code so far (currently only printing the json field url):
import React, {Component} from 'react';
class App extends Component{
constructor()
{
super();
this.state={
data: [],
}
}
componentDidMount()
{
fetch('https://demo7443497.mockable.io/stream/text')
.then((response) => response.json())
.then((findresponse)=>{
console.log(findresponse.url)
this.setState({
data:findresponse.url,
})
})
}
render()
{
return(
<div>
<p> Below there should be some lorem ipsum text: </p>
<p> {this.state.data} </p>
</div>
)
}
}
export default App;
Also if it is not asking too much, I attempted to display a video as well in the exact same way (this json url fiel contains a video instead of text) but for some reason It is only displaying a greyed out video with no content, like it wasn't recognizing the variable I am passing. Did I miss any obvious detail?
Here's my very similar code for displaying the video:
import React, {Component} from 'react';
class App extends Component{
constructor()
{
super();
this.state={
data: [],
}
}
componentDidMount()
{
fetch('https://demo7443497.mockable.io/stream/video')
.then((response) => response.json())
.then((findresponse)=>{
console.log(findresponse.url)
this.setState({
data:findresponse.url,
})
})
}
render()
{
return(
<div>
<video width="400" controls>
<source src={this.state.data} type="video/mp4" />
</video>
</div>
)
}
}
export default App;

text:
import React, {
Component
} from 'react';
class App extends Component {
constructor() {
super();
this.state = {
data: '',
}
}
componentWillMount() {
fetch('https://demo7443497.mockable.io/stream/text')
.then((response) => response.json())
.then((response) => {
// now fetch the text
fetch(response.url)
.then(response2 => response2.text())
.then(response2 => {
this.setState({
data: response2
})
})
})
}
render() {
return (
<div>
<p> Below there should be some lorem ipsum text: </p>
<p> {this.state.data} </p>
</div>
)
}
}
export default App;
video:
import React, {
Component
} from 'react';
class App extends Component {
constructor() {
super();
this.state = {
data: ''
}
}
componentDidMount() {
fetch('https://demo7443497.mockable.io/stream/video')
.then((response) => response.json())
.then((findresponse) => {
console.log(findresponse.url)
this.setState({
data: findresponse.url,
})
})
}
render() {
return (
<div>
{this.state.data
?
<video width="400" controls>
<source src={this.state.data} type="video/mp4" />
</video>
: null}
</div>
)
}
}
export default App;
don't set your state to an array then cast it to string, make it an empty string on the start.
your video example is not working because on first render video is initialized with this.state.data which is an empty array, changing that to a string won't reinitialize video so you need that if statement there
hope it helps :D

If it's a URL, then will re-fetching it works?
componentDidMount()
{
fetch('https://demo7443497.mockable.io/stream/text')
.then((response) => response.json())
.then((findresponse)=>{
console.log(findresponse.url)
fetch(findresponse.url)
.then((urlResp) => urlResp.text())
.then((response) => {
this.setState({
data:findresponse.url,
});
});
});
}
For the video, have tried opening the actual URL on a browser (i.e. Chrome) to check if it's a valid mp4, chrome should be able to easily read it.

You need to re-fetch your inner url in order to retrieve the text:
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = { data: '' }; // set data to string instead of an array
}
componentDidMount() {
fetch('https://demo7443497.mockable.io/stream/text')
.then(response => response.json())
.then(findresponse => fetch(findresponse.url, { mode: 'no-cors' })) // re-fetch
.then(textResp => textResp.text()) // assuming this is a text
.then(data => {
this.setState({ data });
});
}
render() {
return (
<div>
<p> Below there should be some lorem ipsum text: </p>
<p> {this.state.data} </p>
</div>
);
}
}
In other cases (images, video) should be the similar.
Always need to re-fetch the inner url and decide how to process / display final data depending of the type (assuming you can always know)
I just checked your video example and it is a simpler scenario, because findresponse.url (the initial response) has already the resource (image, video) and there is no need to re-fetch.
But, need to change your state.data initialization to an empty string instead of an array to prevent in the first render to initialize the video resource with an empty array. This also could be solved with a spinner.
Keep in mind whenever retrieving resources from server is important to display consistent data, consider a spinner while waiting for the image or video resource, etc.
You need to be careful with all the content you are retrieving, I assume probably you will fetch from another domain. Read about CORS.
Test case:

Related

Not able to fetch data from server in my ReactJs site

Getting undefined data type error while fetching data from JSON
I have searched at many places but didn't get the suitable answer
import SavedData from "./SavedData";
export default class Saved extends React.Component {
constructor() {
super();
this.state = {
loading: true,
datas: [],
};
}
async componentDidMount() {
const url = "https://todo-list-site.herokuapp.com/todo-data";
const response = await fetch(url);
const todoData = response.json().then((res) => {
this.setState({ datas: res });
});
}
render() {
console.log(this.state.datas[0].description); //not able to get data
return (
<div>
{/* {this.state.datas.map((items) => (
<SavedData
key={items.countTodo}
title={items.title}
desc={items.desc}
/>
))} */}
</div>
);
}
}
Someone help me so that I can proceed
Just like Dave Newton has pointed out in the comments, the render is triggered before the request completes. This is normal and you just need to handle it properly.
If you see the console logs of this codesandbox, you can see that initially this.state.datas is just an empty array [] - so any attempt to access this.state.datas[0].description will be undefined. Only after the state is updated when the request completes, the logs show the data retrieved - this is because according to the mount lifecycle of a React Component, the render() is called before the componentDidMount() and also the request being async.
This is very common and it is even recommended by the official React docs to make HTTP calls in componentDidMount(). The docs also has provided an example to handle this issue.
import SavedData from "./SavedData";
export default class Saved extends React.Component {
constructor() {
super();
this.state = {
loading: true, // we initially set this to true
datas: [],
};
}
async componentDidMount() {
const url = "https://todo-list-site.herokuapp.com/todo-data";
const response = await fetch(url);
const todoData = response.json().then((res) => {
this.setState({
datas: res,
loading: false // when the request is complete, we set this to false
});
});
}
render() {
if (this.state.loading) {
// during the first render, loading will be true and we
// can return a loading message or a spinner
return (
<div>Loading...</div>
);
}
// when render is called after the state update, loading will be false
// and this.state.datas will have the fetched data
console.log(this.state.datas[0].description);
return (
<div>
{this.state.datas.map((items) => (
<SavedData
key={items.countTodo}
title={items.title}
desc={items.desc}
/>
))}
</div>
);
}
}
Your datas state is initially an empty array until your componentDidMount fires and sets the state. As a result, your console log will then be undefined until the state is set. In order to combat this you must wait for this.state.datas[0] to be true before accessing the first objects description within the array. The following code seems to work as expected
import React from "react";
export default class Saved extends React.Component {
constructor() {
super();
this.state = {
loading: true,
datas: []
};
}
async componentDidMount() {
const url = "https://todo-list-site.herokuapp.com/todo-data";
const response = await fetch(url);
response.json().then((res) => {
this.setState({ datas: res });
});
}
render() {
console.log(this.state.datas[0] && this.state.datas[0].description);
return (
<div>
{this.state.datas.map((items, i) => (
<div key={i}>
<div> title={items.title}</div>
<div> desc={items.description}</div>
</div>
))}
</div>
);
}
}

Understanding React.JS JSON feed and how to parse

I've got the following code which is looping through an JSON file from an API and loops through some posts.
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
//https://alligator.io/react/axios-react/
import axios from 'axios';
export default class PostList extends React.Component {
state = {
posts: []
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
const posts = res.data;
this.setState({ posts });
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
Pulls in post slugs from Domain
</p>
<ul>
{ this.state.posts.map(post => <li>{post.name} - {post.username} </li>)}
</ul>
</div>
)
}
}
This works fine, and gets the information which was needed.
Now, in my test JSON file, the format is as follows:
https://jsonplaceholder.typicode.com/users
But in my actual JSON file from WordPress Rest API, we have another item, named core_layout:
JSON image
My issue is, trying to use the same code such as {post.name}does not get the information needed such as core_layout->image->name.
Is there an easy way around this?
Thanks all!
EDIT:
Tried the answers below, but still no luck, get the error TypeError: Cannot read property 'map' of undefined:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
//https://alligator.io/react/axios-react/
import axios from 'axios';
export default class PostList extends React.Component {
state = {
posts: [],
coreLayout: {}
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
// const posts = res.data;
//this.setState({ posts });
const { posts, core_layout: coreLayout } = res.data;
this.setState({ posts, coreLayout });
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
Pulls in post slugs from domain
</p>
<ul>
{ this.state.posts.map(post => <li>{post.name} - {post.core_layout.image.name}</li>)}
</ul>
</div>
)
}
}
EDIT 2:
Tried the below: This gets the title, but again, not the actual corelayout I need.
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
movies: []
}
}
componentDidMount() {
let dataURL = "http://zinsseruk.com/wp-json/wp/v2/posts?per_page=1";
fetch(dataURL)
.then(res => res.json())
.then(res => {
this.setState({
movies: res
})
})
}
render() {
let movies = this.state.movies.map((movie, index) => {
return <div key={index}>
<p><strong>Title:</strong> {movie.title.rendered}</p>
<p><strong>Title:</strong> {movie.core_layout.acf_fc_layout}</p>
</div>
});
return (
<div>
<h2>Star Wars Movies</h2>
{movies}
</div>
)
}
}
export default App;
Replace const posts = res.data; with const posts = res.data.core_layout;. Then you'll get an array similar to what you have in your test file.
I think you need to understand the JSON structure you receive from the API. Where is located core_layout property? Inside each post property as a children?
So in the posts loop you can use post.core_layout.image.name for image name, for example (and so on with other properties).
If core_property is at the root of the data you receive, you can load it inside your state like so:
state = {
posts: [],
coreLayout: {}
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
// This is equivalent of doing
// const posts = res.data.posts
// const coreLayout = res.data.core_layout
const { posts, core_layout: coreLayout } = res.data;
this.setState({ posts, coreLayout });
})
}
Then use it in your code by using local component state:
render() {
...
// For example image name:
console.log('image name', this.state.coreLayout.image.name)
...
}

How to use React SetState on nested data with empty top level names?

I have the following JSON data:
[
{"ID":1,"Latitude":"-41.276253","Longitude":"173.283842","Image":"Church.jpg"},
{"ID":2,"Latitude":"-41.267783","Longitude":"173.279114","Image":"Centre.jpg"}
]
I am trying to import it so it can be rendered & started with the following code:
componentDidMount() {
fetch('/home/briefsJson').then(response => response.json()).then(data => {
console.log(data);
this.setState({
latitude: data.Latitude,
longitude: data.Longitude,
image: data.Image
});
});
}
This doesn't as the data is multidimensional/nested. But every example I've found is using better structured data with top level names.
How can I use setState & render to display this data?
If you want to import json from a js file you would do it like this.
Data.js
const Data = [
{"ID":1,"Latitude":"-41.276253","Longitude":"173.283842","Image":"Church.jpg"},
{"ID":2,"Latitude":"-41.267783","Longitude":"173.279114","Image":"Centre.jpg"}
]
export default Data
Then import it where you want to use it. Now you can map through the data as you like.
App.js
import Data from './data'
import React, {Component} from 'react'
class App extends Component {
state = { Data:[] }
componentDidMount() { this.setState({ Data: Data }) }
render() {
return(
<div> {this.state.Data.map(item => <div> The id is: {item.ID} </div> }</div>
)
}
}
Maybe you want to change the names of the items, and return a new data structure with less attributes this is how you would do it.
componentDidMount() {
fetch('/home/briefsJson').then(response => response.json()).then(data => {
const newData = data.map(item => {
latitude:item.Latitude,
longitude: item.Longitude,
image: item.Image}
}
this.setState({
Data:newData
});
});
}
Now if you want to display this data in render.
renderData = () => {
return (
<div>
{this.state.Data.map(item => (
<div>
{item.latitude}
{item.longitude}
<img src={item.img} />
</div>
)}
</div>
)
}
render() {
return (
<div> {this.renderData()} </div>
)
}
It would probably just be easier to first construct what you want, then do a mapping in the rendering. It looks like you don't even need to do anything to convert it, since the json data is exactly what you want in the first place. So:
componentDidMount() {
fetch('/home/briefsJson').then(response => response.json()).then(data => {
console.log(data);
this.setState({ data });
});
}
render() {
return (
<div>
{this.state.data.map(datum => (element))}
</div>
);
}

REACT - fetch json data from url and display it

I am new to REACT and I was trying to learn how to get and display a specific parameter from a json style message stored in an url.
For instance, the video I was trying to show, is stored in and url, which is a field of the json message itself, so it would look like this:
{
"type": "video",
"url": "http://somewebsite.com/wantedvideo.mp4"
}
From what i've read, fetch() is one way to get the data, but unfortunately I couldn't seem to understand what can be missing in the code I tried:
Here's my newbie attempt:
import React, {Component} from 'react';
class App extends Component{
constructor()
{
super();
this.state={
data: [],
}
}
componentDidMount()
{
fetch('https://demo7443497.mockable.io/stream/video')
.then((response) => response.json())
.then((findresponse)=>{
console.log(findresponse.url)
this.setState({
data:findresponse.url,
})
})
}
render()
{
return(
<div>
{this.state.data.url}
</div>
)
}
}
export default App;
My render() always looked suspiciously too simple for me, so my apologies for any "mad" mistakes I may have made
PS: If instead of a video there was some other data format such as an image or plain text in the url of the url field, is there an disavantadge in using the same code to fech it?
Thank you
this.setState({
data: findresponse.url,
})
You are setting url value to data and
in render accessing the data.url. (url on data which does not exists).
If you just put {this.state.data},you will get url value.
Also, if you are getting Object from response then declare state as
this.state = {
data: {}, //instead []
}
EDIT :
e.g. to display video using video control as per comment.
<video width="400" controls>
<source src={this.state.data} type="video/mp4" />
Your browser does not support HTML5 video.
</video>
Working codesandbox
I'm going to provide a simple App component which look like this -
import React, {Component} from 'react';
import { Player } from 'video-react';
class App extends Component{
constructor() {
super();
this.state = {
data: []
}
}
componentDidMount() {
fetch('https://demo7443497.mockable.io/stream/video')
.then( resp => resp.json())
.then((data)=> {
this.setState({
data: data.url
})
})
}
render() {
return(
<Player
playsInline
src={ this.state.data }
/>
)
}
}
export default App;
Import css -
import "node_modules/video-react/dist/video-react.css"; // import css
#import "~video-react/styles/scss/video-react"; // or import scss
Add <link rel="stylesheet" href="/css/video-react.css" /> inside index.html
Try this it will work for all browsers.

Display API data using Axios and a list in React

I'm attempting to make a request to this https://www.themoviedb.org/documentation/api API in a React project and then display JSON data on my site.
I'm using Axios to make the request and I have been able to make the request and get the appropriate JSON data and console.log it or view it in the React tools in Firefox. However, I am having difficulty displaying the data in a ul. Initially I had an error pertaining to having a unique key for each list item, and I have since resolved that (or so I believe).
Here's my request and how I am attempting to render the data:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import axios from "axios";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
posts: []
}
}
componentDidMount() {
axios.get(`https://api.themoviedb.org/3/movie/now_playing?api_key=*apikeyhere*&language=en-US&page=1`)
.then(res => {
const posts = res.data.results.map(obj => [obj.title, obj.overview]);
this.setState({ posts });
});
}
/* render() {
return (
<div>
<h1>Movie API data</h1>
<ul>
{this.state.posts.map(post =>
<li key={post.toString()}>{post.title}</li>
)}
</ul>
</div>
);
}
}
*/
render() {
return (
<ul>
{this.state.posts.map(function(post, index){
return (
<div key={index}>
<h1>{post.title}</h1>
<p>{post.overview}</p>
</div>
)
}
)}
</ul>
);
}
}
As you can see I attempted multile approaches to rendering this. What's wrong with my code and why isn't the JSON data rendering in the ul on my site?
I think, you have an error inside success fuction ({title: obj.title, overview: obj.overview})
componentDidMount() {
axios.get(`https://api.themoviedb.org/3/movie/now_playing?api_key=*apikeyhere*&language=en-US&page=1`)
.then(res => {
const posts = res.data.results.map(obj => ({title: obj.title, overview: obj.overview}));
this.setState({ posts });
});
}