Return Fetched Data from Axios in React - reactjs

Have a question about rendering fetched data with Axios. I’m able to log returned data to the console, however, it will not render on the screen.
I’m using an NPM Bitly module: https://www.npmjs.com/package/bitly
const BitlyClient = require('bitly');
const bitly = BitlyClient('ACCESS TOKEN');
State
class Example extends Component {
constructor() {
super();
this.state = {
landing: 'https://www.google.com/',
newUrl: 'https://www.udacity.com/'
};
API Call
componentDidMount() {
bitly.shorten(this.state.landing)
.then((response) => {
this.setState({newUrl: response.data.url })
console.log(response.data.url);
})
.catch(function(error) {
console.error(error);
});
}
This returns data to the console but does not render to the page.
Render to Page
<Component> {this.newUrl} </>
What am I missing?

It should be {this.state.newUrl}.

Literally started to work as soon as I posted this smh.
I just updated the component to include the state.
Did not work
<Component> {this.newUrl} </>
Does Work
<Component> {this.state.newUrl} </>

Related

How do I re-render react components on url change?

I have a route like so:
<BrowserRouter>
<Switch>
<Route path="/question/:title" component={Item} />
</Switch>
</BrowserRouter>
The component uses axios to fetch data and update the content on the site, this is done in the componentWillMount function:
componentWillMount(){
const {title} = this.props.match.params;
axios.get(server + '/api/question/slug/' + title)
.then(response => {
this.setState({
question: response.data,
loading: false
})
})
}
The problem now is that, let's say I'm on a page "site.com/question/this-is-an-article",
and I use <Link to="/question/second-article">Second Article</Link> to navigate, it's like the componentWillMount function is not being called so the former content still remains on the page.
How can I make the componentWillMount function to run when there is a change in the url?
First of all, use safe life-cycle is preferred react-lifecycle-methods-diagram
Since you are using react-router-dom, you can get your URL via render props like this, refer to document here
history.location.pathname
So you may try to check if url changed in shouldComponentUpdate like this
shouldComponentUpdate(prevProps, prevState) {
return this.props.history.location.pathname !== prevProps.history.location.pathname
}
You can add more condition inside of it, or just prevent complex condition via component design adjustment
Try using the componentDidUpdate for the axios calling. Necessarily - you want to call the api when title(a prop) parameter change.
You may also try componentWillReceiveProps/UNSAFE_componentWillReceiveProps for the same.
P.S. - use componentDidMount along with above aptly. Look for lifecycle here http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
I think you don't need any life cycle, (if yes, just use componentDidMount):
class App extends Component {
constructor() {
super();
this._initHistoryListen();
}
_unListen = () => {};
_initHistoryListen() {
this._unListen = history.listen((location, action) => {
const {
title
} = this.props.match.params;
axios.get(server + '/api/question/slug/' + title)
.then(response => {
this.setState({
question: response.data,
loading: false
})
})
});
}
componentWillUnmount(){
this._unListen()
}
}

Axios "uncancel" api calls

I have a pages and inside have a componentDidMount(). We have API calls, however if you navigate away before those calls are resolved you get React error. You can't setState on an unmounted component. So for this reason I've used Axios cancelToken to cancel API calls in componentWillUnmount(). It's working and API calls are being cancelled.
However if you navigate away, and then come back to the same page, I'm seeing that those API calls are still cancelled and not being resolved. Maybe I've implemented cancelToken the wrong way or is there a way to "uncancel" those calls?
Here's codesandbox:
axios cancelToken example
The problem is creating a cancel token that is created in the scope of the file level. So, the first time it's generated and, after that, the request gets cancelled every time without making the request.
const signal = CancelToken.source();
class Roster extends React.Component {
...........
}
So removed the const signal which is declared before the class Roster and included in the constructor of Roster component.
I have modified the code for the Roster Component taken from your sample code, here:
import React from "react";
import axios, { CancelToken } from "axios";
import request from "./api";
class Roster extends React.Component {
constructor() {
super();
this.state = {
data: null,
error: null
};
this.signal = CancelToken.source();
}
componentDidMount() {
request({ url: "google.com", method: "GET", cancelToken: this.signal })
.then(data => this.setState({ data }))
.catch(error => {
if (axios.isCancel(error)) {
this.setState({ error: "request cancelled" });
}
});
}
componentWillUnmount() {
this.signal.cancel();
}
render() {
const { data, error } = this.state;
return (
<div>
<div>data: {data ? data : "no data"}</div>
<div>error: {error ? error : "no error"}</div>
</div>
);
}
}
export default Roster;

React component is rendering but not updating when state is updating

React component is showing data when state is null but, when its getting data then its not updating the content of the view.
constructor(props){
super(props);
this.state = {
post: null
}
this.getTotalDownloadSize = this.getTotalDownloadSize.bind(this);
}
componentWillMount(){
const {match} = this.props;
const postId = _.get(match, 'params.id');
getDownloadInfo(postId).then((response) => {
this.setState({
post: _.get(response, 'data')
});
}).catch((err) => {
console.log("an error while fetching data", err);
})
}
inside my render i am getting null value for render(){
render(){
const {post} = this.state;
console.log{post};
const files = _.get(post, 'files', []);
)
initially its showing the null value but after it has value but its not updating the content of the view.
can anyone help me with this.
thanks in advance.
componentDidMount is place where you can place request logic.
componentDidMount() {
const {match} = this.props;
const postId = _.get(match, 'params.id');
getDownloadInfo(postId).then((response) => {
this.setState((state) => ({ post: _.get(response, 'data')}));
}).catch((err) => {
console.log("an error while fetching data", err);
})
}
If your data came from an asynchronous request you should use componentDidMount
Invoked once, only on the client (not on the server), immediately
after the initial rendering occurs. At this point in the lifecycle,
you can access any refs to your children (e.g., to access the
underlying DOM representation). The componentDidMount() method of
child components is invoked before that of parent components.
If you want to integrate with other JavaScript frameworks, set timers
using setTimeout or setInterval, or send AJAX requests, perform those
operations in this method.

How do I access axios response promise and use it on my webpage?

How do I gain acceess to promises so that I can use for example the bitcoin price on my website?
axios.get('https://api.coinmarketcap.com/v1/ticker/?convert=EUR&limit=10')
.then(function(response){
console.log(response.data[0].price_usd);
});
Here is a codepen with a sample of the code.
https://codepen.io/albin996/pen/LzLZYX?editors=1112
We should start by noting that external requests should be carefully handled in React so the actual reactivity works well keeping its performance. That's why we're going to create a class to holds this logic in a organized way.
const URL = 'https://api.coinmarketcap.com/v1/ticker/convert=EUR&limit=10';
// Our component now is a full class
class BitcoinDisplay extends React.Component {
constructor(props) {
super(props);
// Start with no response available
this.state = {response: false};
}
// Waits the component to be rendered before calling API
componentDidMount() {
axios.get(URL).then(response => {
// Updates the state with the response
this.setState({ response })
});
}
// Renders the component with the available data
render() {
if(!this.state.response) {
// Show a loading state because data may not be available yet
return 'Loading data...';
} else {
return (<h1>{response.data[0].price_usd}</h1>);
}
}
}
Then, you render it inside the DOM.
ReactDOM.render(BitcoinDisplay, document.getElementById('app'));

Ajax request won't display in react render function

I don't know why the result of my axios promise doesn't show up in the render function. I'm using the create-react-app tools by the way.
_getPrice() {
const url = 'https://api.coinbase.com/v2/prices/BTC-USD/spot';
axios.get(url)
.then(function (response) {
//console.log(response.data.data.amount);
let prices = response.data.data.amount;
return prices;
})
}
render() {
return(<div><h3> {this._getPrice()} </h3></div>);
}
React only re-renders components when either the state or props of the component change. If data changes during the render cycle, but doesn't interact with those variables, then the changes will not show up.
You can save the result of your promise to state as follows:
getInitialState() {
return {prices: undefined}
}
componentDidMount() {
const url = 'https://api.coinbase.com/v2/prices/BTC-USD/spot';
axios.get(url)
.then(function (response) {
//console.log(response.data.data.amount);
let prices = response.data.data.amount;
this.setState({prices: prices});
}.bind(this))
}
render() {
return(<div><h3> {this.state.prices} </h3></div>);
}
first you cant call a function in return in render function and if you want update your view you must update state or props...
When requesting data to the server, the request is async, this means it will take time for the server to respond and the browser will continue the execution, than been said, in your current implementation you are returning a promise in your _getPrice function and then when the server responds you are not doing anything with the data.
The second problem is that react will only re-render the component when there are changes on the state or on the props, and in your current implementation you are not changing any of that.
Here's a sample of how you need to do it in order to make it work.
class YourComponent extends Component {
state = {
prices: 0,
};
componentDidMount() {
const url = 'https://api.coinbase.com/v2/prices/BTC-USD/spot';
axios.get(url)
.then((response) => {
let prices = response.data.data.amount;
this.setState({ prices });
});
}
render() {
const { prices } = this.state;
return(
<div>
<h3> {prices} </h3>
</div>
);
}
}
Good luck!

Resources