How do you render from an api in React? - reactjs

I have successfully changed the state using NASA's api.
Now I would like to display title, image and explanation from the api. I'm a beginner so go easy on me!
I have tried searching and trying different code to no prevail. Wondered if someone on here could shine light on what I have been doing wrong.
this.state = {
picture: "",
date: ""
};
componentDidMount(){
fetch(`https://api.nasa.gov/planetary/apod?api_key=${API_KEY}`)
.then(response => response.json())
.then(json => this.setState({ picture: json }));
};
render(){
return (
<div className="container">
<h1>NASA Picture of the Day</h1>
<form onSubmit={this.handleSubmit}>
(YYYY-MM-DD):
<input
type="text"
id="date"
placeholder="input date"
value={this.state.date}
onChange={this.handleChange}
/>
<button type="submit" disabled={!this.state.date}>
Submit
</button>
</form>
</div>
);
};

Currently a sample response from NASA API is as below: ( NOt sure if it changes in future)
{
"date": "2019-08-04",
"explanation": "Twenty-one years ago results were first presented indicating that most of the energy in our universe is not in stars or galaxies but is tied to space itself. In the language of cosmologists, a large cosmological constant -- dark energy -- was directly implied by new distant supernova observations. Suggestions of a cosmological constant were not new -- they have existed since the advent of modern relativistic cosmology. Such claims were not usually popular with astronomers, though, because dark energy was so unlike known universe components, because dark energy's abundance appeared limited by other observations, and because less-strange cosmologies without a signficant amount of dark energy had previously done well in explaining the data. What was exceptional here was the seemingly direct and reliable method of the observations and the good reputations of the scientists conducting the investigations. Over the two decades, independent teams of astronomers have continued to accumulate data that appears to confirm the existence of dark energy and the unsettling result of a presently accelerating universe. In 2011, the team leaders were awarded the Nobel Prize in Physics for their work. The featured picture of a supernova that occurred in 1994 on the outskirts of a spiral galaxy was taken by one of these collaborations. News: APOD is now available via Facebook in Hindi.",
"hdurl": "https://apod.nasa.gov/apod/image/1908/SN1994D_Hubble_2608.jpg",
"media_type": "image",
"service_version": "v1",
"title": "Rumors of a Dark Universe",
"url": "https://apod.nasa.gov/apod/image/1908/SN1994D_Hubble_960.jpg"
}
To display some information from NASA in the same component (Assuming you want to display details before your submit button click)
let picture = this.state.picture;
return (
<div className="container">
<h1>NASA Picture of the Day</h1>
<h2>{picture.title}</h2>
<img src={picture.url} alt={picture.title}></img>
<p>{picture.explanation}</p>
___________ YOUR FORM INPUT CONTROLS _____________
</div>
);

You're not using this.state.picture anywhere. Simply use whatever data is there to render your image.
I'm not sure what format the data is in but assuming the API returns JSON like:
{ "url": "http://nasa.gov/path/to/image.png" }
Then you just need this somewhere:
{ this.state.picture && <img src={this.state.picture.url} /> }

As you stored data in picture , write this in render
return (<ul>this.pictureToDisplay()</ul>)
pictureToDisplay definition :- (Assuming this to be an array of pictures)
return (this.state.picture.map(item=><li>item</li>))

You can do it this way. Just use a different component for the api data and render it conditionally.
this.state = {
picture: "",
date: ""
};
componentDidMount(){
fetch(`https://api.nasa.gov/planetary/apod?api_key=${API_KEY}`)
.then(response => response.json())
.then(json => this.setState({ picture: json }));
};
render(){
let picture_data = this.state.picture;
return (
<div className="container">
<h1>NASA Picture of the Day</h1>
<form onSubmit={this.handleSubmit}>
(YYYY-MM-DD):
<input
type="text"
id="date"
placeholder="input date"
value={this.state.date}
onChange={this.handleChange}
/>
<button type="submit" disabled={!this.state.date}>
Submit
</button>
</form>
{picture !== "" ? <DataComponent picture={picture} />:<div/>}
</div>
);
};
Your Child Component for showing the Nasa's data. Change your Json from api accordingly I used some random keys.
import React, { Component } from 'react';
class DataComponent extends Component {
render() {
let picture = this.props.picture;
return ( <div>
<h1>{picture.someHeading}</h1>
<img src={picture.someURL}></img>
<p>{picture.someDecription}</p>
</div> );
}
}
export default DataComponent;

Related

Clarity Forms in React, fields not working

I have a body of clarity forms that have been prepared for an Angular application and I'm trying to use them in React. However even getting the simplest form to work is beyond me right now, there's inadequate examples and documentation and I'm not a frontend developer. Based on the almost zero examples I can find I'm guessing very few people are using Clarity Forms in React.
Here's an example form with multiple attempts to get the CdsInput field to do something. Oddly I got onClick to work but I can't type in the field on the form when it displays.
render() {
return (
<main cds-layout="p:lg vertical gap:lg" cds-text="body">
<h1 cds-text="heading">Clarity in React</h1>
{this.state.show ? (
<CdsAlertGroup status="warning">
<CdsAlert onCloseChange={() => this.setState({ show: false })} closable>Hello World</CdsAlert>
</CdsAlertGroup>
) : (
''
)}
<CdsButton status="success" onClick={() => this.setState({ show: true })}>
Show Alert
</CdsButton>
<CdsInput type="text" id="formFields_5" placeholder="Email" defaultValue="DEFAULT TEXT!" onClick={() => this.setState({ show: false })} >
Text inside tags
</CdsInput>
</main>
);
}
So clicking on the field influences the alert so onClick works, but I can't type in the box and it's empty.
I've consulted the example React app on the Clarity Design System website, but it only shows some components and icons, it gives no example of input/select/interactive controls except buttons.
I am aware that React doesn't support WebComponents and so Clarity Forms isn't a natural fit, but when I import #cds/react am I compensating for this deficiency or do I also have to put a ref on the CdsInput ... I did try that but got too many errors about types and other things:
inputRef: React.RefObject<typeof CdsInput>;
constructor(props: any) {
super(props);
this.state = {
show: false,
};
this.inputRef = React.createRef<typeof CdsInput>();
}
componentDidMount() {
this.inputRef.current.nativeElement.then(element => {
element.focus();
});
}
render() {
return (
... <CdsInput ref={this.inputRef} >HEY THERE</CdsInput> ...
Does anyone know of a simple but functional example of a Clarity Form working in React using #cds/react that I could refer to?

How do I replace "br" tags in axios response with actual "br" tags?

using: React, WordPress REST API, Axios
I'm pulling results from a custom post type and when I get the results for the field "acf.other" which is a textbox field, whenever the user inputs a return, it puts either (depending on the cpt settings) a <br /> tag, </p> <p> tags, or nothing, resulting in a running paragraph w/ no formatting. If it puts the tags, then the results show the tag on the site, and doesn't actually use the tags (see img).screenshot of results
export const SingleRecent = () => {
const { singleSlug } = useParams();
const [single,setSingle] = useState([]);
useEffect(() => {
axios.get(recent + singleSlug)
.then(response => {
setSingle(response.data);
})
.catch((error) => {
console.log(error);
})
}, [singleSlug]);
return (
<><div className="pagebg singlePageBg">
<main>
<div className="container notHomeContainer singleContainer">
<div className="gallery notHomeGallery singleGallery">
{single.map(single_recent => <SingleRecentItems key={single_recent.id} single_recent={single_recent} />)}
</div>
</div>
</main>
</div></>
);
}
class SingleRecentItems extends Component {
render() {
let { acf } = this.props.single_recent;
return (
<>
<h1>{acf.title}</h1>
<h4>{acf.style}</h4>
<div className="photos">
<span className="recentPhoto">
<img
src={acf.photo}
alt={acf.title}
/>
</span>
</div>
<div className="otherInfo">
{acf.other}
</div>
<div className="location">
Photo Taken in: {acf.location_other}<br />
{acf.location_city}<br />
{acf.location_state}<br />
{acf.location_country}
</div>
<div className="keywords">
{acf.subject}
</div>
</>
)
}
}
I'd like to take the results of {acf.other} and turn the tags into functional tags so that it will format the results (more or less) the way the user intended. Can I somehow assign {acf.other} to a var, parse and concat, and return the results? Is there a better way?
The general rule is that you don't want to treat your data as code. If this were third-party data, a malicious user might write a <script src="steal-their-cookies.xyz"> into your webpage, which you'd much rather see as "<script src="steal-their-cookies.xyz">" on the page rather than as executed code! Inserting user-generated data into your page as code is a great way to expose yourself to cross-site scripting (XSS) attacks and other page-breaking and data-stealing hazards.
However, in your case, the data is supposed to be code, and is supposed to come from a trusted source. To enable your use-case, React has a dangerouslySetInnerHTML property that allows you to treat this data as code. As in this LogRocket blog, this makes sense for a CMS that has trusted editors submitting rich text, but you should be aware of the hazards and use the property with extreme caution.
<!-- Beware the caveats above. -->
<div className="otherInfo" dangerouslySetInnerHTML={{__html: acf.other}} />
Try parsing the result String to escape the HTML characters. It could look something like this:
parsedResult = response.data
.replace("\\u003c", "<")
.replace("\\u003d", "=")
.replace("\\u003e", ">")
.replace("\\u0026", "&");
It might be the case you'll need to escape more characters. A quick lookup will give you the needed codes.
Hope this helps!

Can't type text in my input fields in my form (Utilizing a React custom hook for input handling)

Ok, I am creating a fairly large form in React (only showing three of the fields here), and thus want to utilize a custom hook for the handling.
I found an article explaining a way to do this, however, when I try to type text in my input fields they don't get filled. My console.log of the e.target values it looks like the field gets reset after each keystroke. What do I miss? Cheers
I tried to simplify my code, and hope it makes sense:
import React, { useState } from "react";
//various other imports not relevant for this issue
const NetworkConfig = () => {
//Custom Hook inserted here for easy overview. Normally imported from external file
function useFormFields(initialState) {
const [fields, setValues] = useState(initialState);
return [
fields,
(e) => {
setValues({
...fields,
[e.target.id]: e.target.value,
});
},
];
}
const [fields, handleFieldChange] = useFormFields({
apnValue: "",
apnUsernameValue: "",
apnUserPwdValue: "",
});
// I omitted the submit button and its functionality in this post,
// to keep my problem clear
// The TextField component basicaly just adds some functionality not
// relevant to this problem. It is tested in other scenarios so in this
// case it basically just works as a normal HTML input[type="text"] field
return (
<div>
<div className="network-config-modal" id="network-config">
<div>
<div>
<h2>Network Config</h2>
</div>
<div className="network-config-row">
<div className="network-config-col">
<h3>Cellular Settings</h3>
<section className="network-config-section">
<TextField
value={fields.apnValue}
onChange={handleFieldChange}
label="APN"
outerLabel={true}
light={true}
type="text"
name="apn"
id="apn"
/>
<TextField
onChange={handleFieldChange}
value={fields.apnUsernameValue}
label="APN Username"
optional={true}
outerLabel={true}
light={true}
name="apn-username"
id="apn-username"
/>
<TextField
onChange={handleFieldChange}
value={fields.apnUserPwdValue}
label="APN Password"
optional={true}
outerLabel={true}
light={true}
name="apn-password"
id="apn-pwd"
/>
</section>
</div>
</div>
</div>
</div>
</div>
);
};
export default NetworkConfig;

how to improve my coding standards to meet senior developer standards

I just recently finished a tech test for a company applying for a frontend developer working in react and I was rejected with no feedback. So I was wondering what I could have done better and improved for next time. I've just recently tried to apply for seniors frontend roles. Here is the test they gave me and what I produced.
Here is the description of their test.
Create a component as a Form Control according to this design
The control should accept a label
The control should accept a validation function with configurable error message
The control can be incorporated inside a <form> and the selected option pushed up to the form.
The control should fire an event on change
Use the component you made in the previous step to create a form according to this design
Call this https://jsonplaceholder.typicode.com/users to populate list of the users. name should be displayed while id should be saved as the value in the form.
Add the required validation with the Please select a user error message.
Add 2 text fields, one for title and one for body both with required validation. (Don't worry about matching the design for the text fields.)
On submit of the form create a new post by sending the data to https://jsonplaceholder.typicode.com/posts. The request interface will look like
{
"title": "foo",
"body": "bar",
"userId": 1
}
This is what I produced:
https://codesandbox.io/s/objective-thunder-322xi?file=/src/components/FormComponent.js
I am aware it could have been better but there was a time limit and there was no feedback provided so I don't know where I went wrong. Could someone look through it please and see if it aligns with their instructions and where it could be improved.
I went through your code and may have found some codes which I may have implemented a little differently. I am not sure if this is the best coding standard but may have gone like this.
I see a lot of useStates declared there(7 declarations). I might have group some related states together. I have given an example for reference below. Using too many declarations may not be good in some cases.
The handleChange function (const handleTitleChange = (ev) => setTitle(ev.target.value);) can be improved. The way handled here is repeating for every input. So, if I have 10 inputs, there will be 10 lines for handleChange function. I gave a better way of handling change in my example. Remember to put the same 'name' attribute in the input field and the state. This code will save you a lot of time in future handling onChange and also clean code
I see you use 'id' attribute to refer to DOM elements in the form. This is good for vanilla JS but in React, it is preferred not to use. There is a better way in react called creating a reference, i.e. React.createRef(). This provides an easy reference to the DOM elements. Please refer to my example below.
The validation handling method can be improved. Code in example.
I see the error message does not go away once you fill content. So, this needs to be changed.
I have managed to come up with another way to implement which is totally dependent on states for form validation handling.
CODE WITH CREATE REF Don't mind the CSS classes, I used bootstrap
import React, { useState, useEffect } from 'react';
const TestComponent = () => {
const [input, setInput] = useState({
title: '',
body: '',
})
const titleRef = React.createRef()
const bodyRef = React.createRef()
const handleChange = e => {
setInput({ ...input, [e.target.name]: e.target.value })
}
const onHandleSubmit = e => {
e.preventDefault();
input.title ? titleRef.current.innerHTML = '' : titleRef.current.innerHTML = 'Please add a title';
input.body ? bodyRef.current.innerHTML = '' : bodyRef.current.innerHTML = 'Please add a body';
if (!input.title || !input.body) {
return false;
}
console.log('Submit your form');
}
return (
<div className="container py-5">
<form onSubmit={onHandleSubmit}>
<label>Title</label>
<input type="text" name="title" value={input.title} onChange={handleChange} className="form-control" />
<p ref={titleRef} style={{ color: 'red' }}></p>
<label>Body</label>
<input type="text" name="body" value={input.body} onChange={handleChange} className="form-control" />
<p ref={bodyRef} style={{ color: 'red' }}></p>
<button>Submit</button>
</form>
</div>
);
}
export default TestComponent;
CODE WITH STATES FOR VALIDATION
import React, { useState, useEffect } from 'react';
const TestComponent = () => {
const [input, setInput] = useState({
title: '',
body: '',
titleError: '',
bodyError: '',
})
const handleChange = e => {
setInput({ ...input, [e.target.name]: e.target.value })
}
const onHandleSubmit = e => {
e.preventDefault();
setInput({
...input,
titleError: input.title ? '': 'Please add a title',
bodyError: input.body ? '': 'Please add a body',
})
console.log(input);
if (!input.title || !input.body) {
return false;
}
console.log('Submit your form');
}
return (
<div className="container py-5">
<form onSubmit={onHandleSubmit}>
<label>Title</label>
<input type="text" name="title" value={input.title} onChange={handleChange} className="form-control" />
<p style={{ color: 'red' }}>{input.titleError}</p>
<label>Body</label>
<input type="text" name="body" value={input.body} onChange={handleChange} className="form-control" />
<p style={{ color: 'red' }}>{input.bodyError}</p>
<button>Submit</button>
</form>
</div>
);
}
export default TestComponent;
P.S. There will be much better ways to handle according to the scenario, but this may help you in some way.
EDIT:
Adding Radio button to select the user.
userId added to state
const [input, setInput] = useState({
title: '',
body: '',
titleError: '',
bodyError: '',
userId: '',
})
Radio select for users.
<div>
<input type="radio" name="userId" value="1" id="1"
checked={input.userId === "1"} onChange={handleChange}
/>
<label htmlFor="1">User 1</label>
</div>
<div>
<input type="radio" name="userId" value="2" id="2"
checked={input.userId === "2"} onChange={handleChange}
/>
<label htmlFor="2">User 2</label>
</div>
The same onChange handler will work for the radio select also. I see you use the response from useFetch to render the users. You can use same map logic to render this radio by setting the fields. Set the value and id attribute to user id from response and so on.
One immediate issue I found is a console error.
Production quality code from a Sr. level developer should not be doing this. I would expect to see errors in console if a bug was found or dealing with some edge case.
Warning: Failed prop type: Invalid prop buttonSelectedof typebooleansupplied toButton, expected string`.
in Button (at FormComponent.js:21)
in FormComponent (at App.js:8)
in div (at App.js:7)
in App (at src/index.js:9)
in StrictMode (at src/index.js:8)`
I found this in the console just browsing to the link you shared. There are other things to clean up but this is the most obvious thing I've found so far.

How can I on Submit my Form redirect the Results to another Page in React

I am trying to get the search results to display on another page in React Js. For now, when I submit my search form, it will display the results on the same page which I don't want. I have been trying to do this for the past 4 hours (I am new to ReactJS) and I have been seeing a lot of suggestions online but nothing seems to work as I was hoping.
I have even tried to use react redux, react router and much more example online but does not work, don't what I'm doing wrong.
How can I approach it? I would please like someone to probably put me on the right track in regards to the code I provide below and also your suggestions/feedback are welcome.
Thank you in advance.
Here is my search engine component responsible for the form
const SearchEngine = (props) => {
return (
<div>
<h3 className="spacer">Search Engine</h3>
<form onSubmit={props.getTrend}>
<div class="input-group md-form form-sm form-2 pl-0">
<input class="form-control my-0 py-1 red-border" type="text" name="keyword" placeholder="Enter your keyword" aria-label="Search" />
<div class="input-group-append">
<button class="input-group-text red lighten-3" id="basic-text1"><i class="fa fa-search text-grey" aria-hidden="true"></i></button>
</div>
</div>
</form>
</div>
);
}
export default SearchEngine;
and here is the result component where I would like to display the results
const Results = (props) => (
<div>
Hello
</div>
);
export default Results;
After receiving your api calls you can throw a push and move to another page. For yours it may look something like this.
getTrend = async (e) => {
e.preventDefault();
const keyword = e.target.elements.keyword.value;
const api_call = await fetch(`http://localhost:8081/trend/twitter?keyword=${keyword}`); //make API call
const data = await api_call.json();
if (keyword) {
this.setState({
tweets: data
});
console.log(this.state.tweets);
this.props.history.push({
pathname: '/results',
state: { detail: data }
})
}
else {
this.setState({
tweets: undefined,
error: "Please enter the values"
});
}
}
Then, in your App.js you can access it with
props.location.state.detail
This may require that you use withRouter as a HOC. One thing I would change is grab your api in componentDidMount. However, it would be much easier if you went about this with hooks. While it may require some refractoring, you could make your api call with a hook, which is a ton simpler to get up and running.

Resources