I cannot get image to render after a network query - reactjs

Using Parse, I am querying the database and getting an imageURL back. React is not updating the dom.
componentWillMount and just regular curly brackets.
export const profileImage = async objectId => {
const query = new Parse.Query(Parse.User);
query.equalTo("objectId", objectId);
const image = await query.find();
console.log(typeof image[0].attributes.image);
console.log(image[0].attributes.image);
return image[0].attributes.image; // return image;
}; // Query for a specific user and get image!
I imported it currently and it does the console logs so the function is executing but never rendering.
export default class MyDashboard extends Component {
constructor(props) {
super(props);
this.state = {
profilePic: "",
};
}
componentDidMount() {
this.setState({ profilePic: profileImage(window.localStorage.objectId) });
}
render() {
return (
<div>
<Sidebar />
<div className={style.Componentcontainer} />
<div className={style.main}>
</div>
<div className={style.profile}>
<div> {this.state.profilePic} </div>
}
I eventually plan to put the string into an image tag, I just got to get this rendering first.

Your function is asynchronous, so setState will not wait and will render undefined.
To fix this, you should return a promise, and consume it with a .then() and set the state there instead. You should also use window.localStorage.getItem(), rather than trying to access a property immediately.
export const profileImage = objectId => {
const query = new Parse.Query(Parse.User);
query.equalTo("objectId", objectId);
return query.find();
};
export default class MyDashboard extends Component {
constructor(props) {
super(props);
this.state = {
profilePic: ""
};
}
componentDidMount() {
profileImage(window.localStorage.getItem(objectId)).then(image => {
this.setState({ profilePic: image[0].attributes.image });
});
}
render() {
return (
<div>
<Sidebar />
<div className={style.Componentcontainer} />
<div className={style.main} />
<div className={style.profile}>
<img src={this.state.profilePic} />
</div>
</div>
);
}
}

Related

React JS can't able to render components from Array

When i try to render my component using map function it show error that this.state.articles is undefined but it work well when i use map function on componentDidMount() OR other functionsenter image description here
import React, { Component } from 'react'
import Items from './Items'
export default class News extends Component {
constructor() {
super()
this.state = {
articles: this.articles
}
}
async componentDidMount() {
let GET = 'https://newsapi.org/v2/top-headlines?country=us&apiKey=256fd7f5eed44e16b08f3e23cb2dabdb'
let Data = await fetch(GET)
let parse = await Data.json()
this.setState({ articles: parse.articles })
}
render() {
return (
<div className='container my-3'>
<h1>R News | Top Headlines</h1>
<div className='row'>
{
this.state.articles.map((ele)=>{
return <div></div>
})
}
</div>
</div>
)
}
}
k.imgur.com/ALxmx.png
I see that you're using this.articles in the constructor but I don't see it declared anywhere in your class. I think you meant to initialize your state with an empty array and you retrieve the articles from the backend:
constructor() {
super()
this.state = {
articles: []
}
}
The reason is because it takes time for the information to get back from newsapi.org so you can either use a async function or add a '?' which will be a check to see whether the article that came back from newsapi is back or not.
Try this render
return (
<div className='container my-3'>
<h1>R News | Top Headlines</h1>
<div className='row'>
{
this.state.articles?.map((ele, index)=>{
return <div key={index}></div>
})
}
</div>
</div>
)
This is because articles are undefined when the data is not yet loaded try this code,
import React, { Component } from 'react'
import Items from './Items'
export default class News extends Component {
constructor() {
super()
this.state = {
articles: this.articles
}
}
async componentDidMount() {
let GET = 'https://newsapi.org/v2/top-headlines?country=us&apiKey=256fd7f5eed44e16b08f3e23cb2dabdb'
let Data = await fetch(GET)
let parse = await Data.json()
this.setState({ articles: parse.articles })
}
render() {
return (
<div className='container my-3'>
<h1>R News | Top Headlines</h1>
<div className='row'>
{
this.state.articles && this.state.articles.map((ele)=>{
return <div></div>
})
}
</div>
</div>
)
}
}

Unhandled Rejection (TypeError): Cannot read property 'setState' of undefined

I know that there are plenty of answers on this, for example this one. I did add the .bind(this) in the component constructor. I also tried the fat arrow method (fakeApiCall = ()=>{ ... }) but when I click Change Me, this error still displays:
import React, { Component } from 'react';
import axios from 'axios';
class App extends Component {
constructor(props){
super(props);
this.state = {
count : 1000
};
this.fakeApiCall = this.fakeApiCall.bind(this);
}
fakeApiCall (){
axios.get('https://jsonplaceholder.typicode.com/users')
.then(function(response){
// the response comes back here successfully
const newCount = response.data.length;
// fail at this step
this.setState({ count : Math.floor(newCount) });
});
}
render() {
return (
<div className="App">
<span style={{ fontSize : 66 }}>{this.state.count}</span>
<input type='button' onClick={this.fakeApiCall} value='Change me' />
</div>
);
}
}
export default App;
Your fakeApiCall function is bound to your context, but the function callback in axios is not.
To solve this, you can use an arrow function, as they automatically bind with your class. You can also do it for fakeApiCall and remove it's binding :
class App extends Component {
constructor(props) {
super(props);
this.state = {
count: 1000
};
}
fakeApiCall = () => {
axios.get('https://jsonplaceholder.typicode.com/users')
.then(response => { //This is an arrow function
const newCount = response.data.length;
this.setState({ count: Math.floor(newCount) });
});
}
render() {
return (
<div className="App">
<span style={{ fontSize: 66 }}>{this.state.count}</span>
<input type='button' onClick={this.fakeApiCall} value='Change me' />
</div>
);
}
}

React: Issues with Conditional Rendering

In my React-App, i use the Firebase SDK. If a user wants to reset his password, he will be redirected to a page within my app. If the code is valid, the component <PWResetConfirmForm /> should be rended. If the code is invalid, the component <PWResetOutdatedForm /> is to be rendered.
My Page Component looks like this:
class PWResetConfirmPage extends Component {
constructor(props) {
super(props);
this.state = {};
this.verfiyResetPassword = this.verfiyResetPassword.bind(this);
}
verfiyResetPassword() {
const params = (new URL(`http://dummy.com${this.props.location.search}`)).searchParams;
const code = params.get("oobCode")
auth.doVerfiyPasswordReset(code)
.then(function () {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetConfirmForm></PWResetConfirmForm>
</div>
);
})
.catch(function () {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetOutdatedForm></PWResetOutdatedForm>
</div>
);
})
}
render() {
return (
<div>
{this.verfiyResetPassword()}
</div>
);
}
}
export default PWResetConfirmPage
When i try to run, i get a blank page and not error.
Where is my issue and how can i fix that?
Thank you very much for your help and for your time
You will not be able to return JSX from within then()/catch() of auth.doVerfiyPasswordReset() like that. You can instead approach this by taking advantage of React.Component lifecycle method componentDidMount and using setState() to manipulate state properties for conditional rendering. I've added state properties to the component, one to track whether loading (API call has completed) and one to track whether the call was a success (then) or failure (catch). These properties are used to conditionally generate JSX content for rendering. This is assuming that verfiyResetPassword() is intended to run when the component is first mounted, instead of every time render() is called:
class App extends Component {
constructor() {
super();
this.state = {
isResetVerified: null,
loading: true
};
}
componentDidMount() {
this.verfiyResetPassword();
}
verfiyResetPassword() {
const params = (new URL(`http://dummy.com${this.props.location.search}`)).searchParams;
const code = params.get("oobCode")
auth.doVerfiyPasswordReset('foobar')
.then(() => {
this.setState({
...this.state,
isResetVerified: true,
loading: false
});
})
.catch(() => {
this.setState({
...this.state,
isResetVerified: false,
loading: false
});
})
}
getContent() {
if (this.state.loading) {
return (
<div>Loading...</div>
);
} else {
if (this.state.isResetVerified) {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetConfirmForm></PWResetConfirmForm>
</div>
);
} else {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetOutdatedForm></PWResetOutdatedForm>
</div>
);
}
}
}
Here is a basic example in action.
Also, in the constructor this.verfiyResetPassword = this.verfiyResetPassword.bind(this); would only be needed if verfiyResetPassword() is executed by a DOM event such as button onClick or similar.
Hopefully that helps!
I could still fix the error myself:
class PWResetConfirmPage extends Component {
constructor(props) {
super(props);
this.state = {
isValid: false,
code: "",
};
this.verfiyResetPassword = this.verfiyResetPassword.bind(this);
}
componentDidMount() {
const params = (new URL(`http://dummy.com${this.props.location.search}`)).searchParams;
const code = params.get("oobCode")
this.setState({code:code})
auth.doVerfiyPasswordReset(code)
.then(() => {
this.setState({
...this.state,
isValid: true,
});
})
.catch(() => {
this.setState({
...this.state,
isValid: false,
});
})
}
verfiyResetPassword() {
if (this.state.isValid) {
return (
<div>
<TopBar></TopBar>
<PWResetConfirmForm code={this.state.code}></PWResetConfirmForm>
</div>
);
} else {
return (
<div>
<TopBar></TopBar>
<PWResetOutdatedForm></PWResetOutdatedForm>
</div>
);
}
}
render() {
return (
<div className="HomePage-Main">
{this.verfiyResetPassword()}
</div>
);
}
}
export default PWResetConfirmPage

Right way to update data in ReactJS

what is the right way in ReactJS to update and display the correct value.
Example: I show data on the screen from a database. When I change the values in the database I want to see the new values directly on the screen.
I have two files:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
containers: []
};
}
componentDidMount() {
var self = this;
axios.get('http://reactlaravel.dev/container/count').then(function (response) {
self.setState({
containers: response.data
});
})
}
render() {
const containers = this.state.containers.map( (container, i) => <StockCount key={i} {...container} /> );
return (
<div>
{containers}
</div>
)
}
const Container = ({ name, total, current }) => (
<div>
<span>{name}</span>
<span>{total}</span>
<span>{current}</span>
</div>
);
ReactDOM.render(
<Parent />,
document.getElementById('app')
);
And the second file:
export class StockCount extends React.Component {
render() {
const currentBar = this.props.current;
const totalBar = this.props.total;
const progressBar = currentBar / totalBar * 100;
return (
<div className="container">
<h1>{this.props.current} - {this.props.total} - {this.props.name}</h1>
<div className="progress">
<div className={progressBarType} role="progressbar" aria-valuenow={progressBar} aria-valuemin="0" aria-valuemax="100" style={style}>
<span className="sr-only">{progressBar}% Complete (success)</span>
</div>
</div>
</div>
);
}
You have to implement server push (will require server changes) in order to notify client app about database changes. Here is easiest way to go without server modifications short pulling:
componentDidMount() {
this.lookupInterval = setInterval(() => {
axios
.get('http://reactlaravel.dev/container/count')
.then(function(response) {
this.setState({
containers: response.data,
})
})
}, 500)
}
componentWillUnMount() {
clearInterval(this.lookupInterval)
}
Use a life cycle method for updating? like componentWillReceiveProps() https://reactjs.org/docs/react-component.html

Passing a function in props to a component

I'm new to react and trying to pass a global function to components to avoid repeating it in each of them. That doesn't work, I get an undefined error when I try to call it in the components.
Here is my code :
import React from 'react';
//components
import League from './League';
class App extends React.Component {
state = {
leagues: {},
};
componentDidMount() {
this.getLeagues();
}
get(url) {
var myHeaders = new Headers();
myHeaders.append("Accept", "application/json");
myHeaders.append("X-Mashape-Key", "mysecretkeyblablabla");
var myInit =
{
headers: myHeaders
};
return fetch(url,myInit)
.then(function(response) {
if(response.ok) {
return response.json().then(function(json) {
return json.data;
});
}
});
};
getLeagues() {
this.get('https://sportsop-soccer-sports-open-data-v1.p.mashape.com/v1/leagues').then((data) => {
this.setState({leagues: data.leagues});
});
}
render() {
const leagues = Object
.keys(this.state.leagues)
.map(key => <League get={this.get} key={key} details={this.state.leagues[key]} />
);
return(
<div className="App">
<div className="App-header">
<h1>Welcome to Foot Stats app (made in ReactJS)</h1>
</div>
<p className="App-intro">
Here is the place where I should put the countries.
</p>
<ul>
{leagues}
</ul>
</div>
);
};
}
export default App;
and my League component
import React from 'react';
import Season from './Season';
class League extends React.Component {
state = {
seasons: {},
};
constructor(props) {
super(props);
}
componentDidMount() {
//this.getSeasonsAvailable(this.props.details.league_slug);
}
getSeasonsAvailable(league) {
const url = 'https://sportsop-soccer-sports-open-data-v1.p.mashape.com/v1/leagues/{league_slug}/seasons'.replace('{league_slug}',league);
const seasons = [];
console.log(this.props);
this.props.get(url).then((data) => {
data.seasons.map(function(object, i) {
seasons[data.seasons[i].identifier] = data.seasons[i];
});
this.setState({seasons: seasons});
});
};
render() {
const seasons = Object
.keys(this.state.seasons)
.map(key => <Season key={key} league_slug={this.props.details.league_slug} details={this.state.seasons[key]} />
);
return (
<li>
<span onClick={this.getSeasonsAvailable.bind(this.props.details.league_slug)}>{this.props.details.nation} : {this.props.details.name}</span>
<ul>
{seasons}
</ul>
</li>
);
}
static propTypes = {
get: React.PropTypes.func.isRequired
};
}
export default League;
When I click on the season component, I get this error :
Cannot read property 'get' of undefined
And my console.log(this.props) returns me undefined.
Thanks !
You just need to change
<span onClick={this.getSeasonsAvailable.bind(this.props.details.league_slug)}>
to
<span onClick={this.getSeasonsAvailable.bind(this, this.props.details.league_slug)}>
Apart from this, if you want to use ES6 way to do this. You can use arrow functions
<span onClick={() => this.getSeasonsAvailable(this.props.details.league_slug)}>
or you can bind the function getSeasonsAvailable in the constructor using
constructor() {
super();
this.getSeasonsAvailable = this.getSeasonsAvailable.bind(this);
}
You can read in more detail about it here and here.
Because your onClick: .bind(this.props.details.league_slug)
what is this.props.details.league_slug actually?
bind will change the reference of this in getSeasonsAvailable (this will ref to this.props.details.league_slug, I don't know what it is), of course you will get undefined when you call this.props
Try just .bind(this), so the this in getSeasonsAvailable can ref to the component itself.

Resources