Reputation: 367
So I have this application that displays random quotes that are pulled as JSON data from an API. It's my first foray into React so it is not really well done. Initially, I had all of my code stored in one component - but this was obviously not best practices because I had multiple things that could be split into components, i.e. a quote, a footer, a share button.
The issue I ran into when I split it up is that I didn't know how to share state between component files (for sharing to Twitter or other additional features) because I fetch the data like this:
/* this function accesses the API and returns a json */
export default function fetchQuote() {
return fetch('https://programming-quotes-api.herokuapp.com/quotes/random') // fetch a response from the api
.then((response) => {
let json = response.json(); // then assign the JSON'd response to a var
return json; // return that bad boy
});
}
which originally was called within the component class like so:
/* component for the quotes */
export default class Quote extends React.Component {
/* placeholder */
constructor(props) {
super(props);
this.state = {
quoteAuthor: "Rick Osborne",
quote: "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
}
}
/* actually render things */
render() {
return (
<div className="quotes">
<h1>{this.state.quoteAuthor}</h1>
<p>{this.state.quote}</p>
<div className="button">
<button id="button" onClick={this.update}>New quote</button>
</div>
</div>
);
}
/* async fetch the quotes and reassign the variables to them once processed */
update = async() => {
let response = await fetchQuote();
console.log(response);
this.setState({
quoteAuthor: response.author,
quote: response.en
});
};
}
From my understanding, React's hooks seemed to solve my problem because I could use useState
and useEffect
which I tried to implement as follows (with the original fetchQuote()
function untouched):
export default function Quote() {
const [author, setAuthor] = useState("Rick Osborne");
const [quote, setQuote] = useState(
"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
);
let json = fetchQuote();
useEffect (() => {
setAuthor(json.author);
setQuote(json.quote);
console.log(json);
});
return (
<div className="quotes">
<h1>{author}</h1>
<p>{quote}</p>
<div className="button">
<button id="button" onClick={async () => json = await fetchQuote()}>
New quote
</button>
</div>
</div>
)
}
However, no errors are thrown except the area in which the quote is displayed shows empty and calling console.log(json)
within the useEffect
simply returns
Promise { <state>: "pending" }
Promise { <state>: "pending" }
Am I using Hooks properly? How can I properly update the state with the JSON data?
Upvotes: 1
Views: 1748
Reputation: 5304
It looks like the promise from fetch isn't resolving. Try this:
export default Quote = () => {
const [author, setAuthor] = useState("Rick Osborne");
const [quote, setQuote] = useState('');
const fetchMyAPI = async () => {
let json = await fetchQuote();
setAuthor(json.author);
setQuote(json.quote);
}
useEffect(() => {
fetchMyAPI();
}, []);
return (
<div className="quotes">
<h1>{author}</h1>
<p>{quote}</p>
<div className="button">
<button id="button" onClick={fetchMyAPI}>
New quote
</button>
</div>
</div>
)
This called fetchMyAPI onMount, and calls it whenever you click on New Quote
.
Upvotes: 3