ternary operator issue in React return - reactjs

I'm trying to use a return with a ternary. But I have an error saying Unexpected token, expected "," (31:21) on the dot of Object.keys but I don't know what is it. I would like some help to figure it out, please.
import React, { Component } from 'react';
import SpotifyLogin from 'react-spotify-login';
import axios from 'axios';
import '../style.css';
import SelectWidget from './SelectWidget';
class SpotLogin extends Component {
state = {
authData: {}
}
stockInfo = (e) => {
this.setState({
authData: e
});
}
getUserInfo() {
axios('https://api.spotify.com/v1/me', {
method: 'GET',
headers: {'Authorization' : 'Bearer ' + this.state.authData.access_token}
})
.then(data => {
console.log(data.data);
})
}
render() {
return(
{ Object.keys(this.state.authData).length === 0 ? (
<div>
<SpotifyLogin clientId = MY_ID
redirectUri = 'http://localhost:3000/callback'
onSuccess={this.stockInfo}
buttonText= "Spotify"
className= "btn-spotify"
/>
</div>
) :
<div>
<SelectWidget />
</div>
}
)
}
}
export default SpotLogin;

You only need curly braces inside JSX. The Object.keys statement isn't technically inside the JSX, it's just being directly returned. So try removing the curly braces around it:
render() {
return(
Object.keys(this.state.authData).length === 0 ? (
<div>
<SpotifyLogin clientId = MY_ID
redirectUri = 'http://localhost:3000/callback'
onSuccess={this.stockInfo}
buttonText= "Spotify"
className= "btn-spotify"
/>
</div>
) :
<div>
<SelectWidget />
</div>
)
}

Related

Cannot insert input text to url in fetch api

I am trying to insert the value of my stateful variable (myValue) to the api url after q=
I tried using ${} but it is not working.
It is working when I insert text righ in to url, but I need to insert the input variable. ( sorry for messy code, I am a beginner )
p.s ignore the api key, I just replace it with *** here.
import React, { createRef } from "react";
import { Component } from "react";
import { Button, TextField } from "#mui/material";
import WeatherCard from './components/WeatherCard'
class App extends Component {
constructor(props) {
super(props);
this.textInput = createRef();
this.state = {
myValue: "",
temp : ""
};
}
showRefContent = () => {
this.setState({
myValue: this.textInput.current.value
});
const uriEncodedCity = encodeURIComponent(this.state.myValue);
fetch('https://api.openweathermap.org/data/2.5/weather?q=madrid&appid=***')
.then(response => response.json())
.then(data => this.setState({
temp : data.main.temp
}),
console.log(this.state.temp)
);
}
handleChange = (e) =>
this.setState({
myValue: e.target.value
});
render() {
return (
<div >
<div >
<TextField inputRef={this.textInput}
id="demo-helper-text-misaligned-no-helper" label="City name"
/>
<br></br>
<Button margin = "right:20" size="large" variant ="contained" onClick={this.showRefContent}>Get Weather</Button>
</div>
<p>
{this.state.myValue.length > 0
? <WeatherCard temp = {this.state.temp} />
: "no text"}
</p>
</div>
);
}
}
export default App;
Did you use `` or '' with ${}. Make sure you use ``.
fetch(`https://api.openweathermap.org/data/2.5/weather?q=${}&appid=***`)

React this.props.id is undefined in part of class

In my React application I need the userId in the Timeline class to get the posts from a user, but React says that it's undefined.
If I say in the rendered part
{ this.props.id }
Than it will show the right id..
I already tried every solution that I could possibly find on the internet.
import React, { Component } from 'react'
import axios from 'axios'
import Timeline from './Timeline'
class Profile extends Component{
state = {
user: {}
}
componentDidMount() {
axios.get(`http://localhost:8090/user/${this.props.match.params.id}`)
.then(res =>{
const user = res.data
this.setState({ user: user })
})
}
render(){
return(
<div>
<h1>This is the profile page of { this.state.user.username }.</h1>
<img src={this.state.user.profilePicture} ></img>
<h3> E-mailaddress: { this.state.user.mail }</h3>
<Timeline id={this.state.user.id}/>
</div>
)}
}
export default Profile
import Cookies from 'universal-cookie'
import React, { Component } from 'react'
import axios from 'axios'
const cookies = new Cookies()
class Timeline extends Component {
state = {
user: cookies.get('user'),
posts: []
}
componentDidMount() {
const id = this.props.id
console.log("ID IS " + id)
if (this.state.user === undefined)
return
axios.get(`http://localhost:8090/user/${id}/postEntities`)
.then(response => {
this.setState({
posts: response.data._embedded.post
})
})
.catch(error => {
console.log(error)
})
}
render() {
if (this.state.user !== undefined) {
if (this.state.posts.length <= 0) {
return (
<main>
<h2>Personal timeline</h2>
<h2>This id works: { this.props.id }</h2>
<h6>There does not seem to be anything here..<br />Create a post and come back later!</h6>
</main>
)
} else {
return (
<main>
<h2>Personal timeline</h2>
{
this.state.posts.map(post => {
return (
<div>
<h5>{ post.title }</h5>
<img src={post.pictureUrl} width="200" height="200"></img>
<p><i>You took this picture at { post.longitude }, { post.latitude }</i></p>
</div>
)
})
}
</main>
)
}
}
else {
return (
<h5>You need to be logged in to use this feature</h5>
)
}
}
}
export default Timeline
The expected output in the url needs to be 2 but is undefined, the expected value in the rendered part is 2 and it outputs 2.
With react, the componentDidMount of children is called BEFORE the one from the parent.
So, when the componentDidMount of Timeline is called the first time, the componentDidMount of Profile has not been called, so there is no userId yet.
To avoid this problem, you should render the Timeline only when the Profile component has been mounted and when you have your user id.
So something like that in the render of Profile
render(){
return(
<div>
<h1>This is the profile page of { this.state.user.username }.</h1>
<img src={this.state.user.profilePicture} ></img>
<h3> E-mailaddress: { this.state.user.mail }</h3>
{this.state.user.id && (
<Timeline id={this.state.user.id}/>
)}
</div>
)}
Because
this.state.user.id
only has value when function axios.get in componentDidMount has done. while function render() is called before.
So, To avoid undefined, you must set state with format:
state = {
user: {id : 0} //or null
}
Initially you won't have user.id, it is coming from axios service call. In this case wait till you get response and then show timeline based on condition in render.
import React, { Component } from 'react'
import axios from 'axios'
import Timeline from './Timeline'
class Profile extends Component{
state = {
user: {}
}
componentDidMount() {
axios.get(`http://localhost:8090/user/${this.props.match.params.id}`)
.then(res =>{
const user = res.data
this.setState({ user: user })
})
}
render(){
return(
<div>
<h1>This is the profile page of { this.state.user.username }.</h1>
<img src={this.state.user.profilePicture} ></img>
<h3> E-mailaddress: { this.state.user.mail }</h3>
{typeof(this.state.user.id) !== 'undefined' ? <Timeline id={this.state.user.id}/> : ''}
</div>
)}
}
export default Profile
What variable is undefined? this.state.user.id?
If so, that probably means that you start with user: {}, then you make a promise and then set the state. The problem is that a promise will take time to fulfill, so meanwhile you are still with user: {} and this.state.user.id gives undefined.
When you call <Timeline id={this.state.user.id}/> make sure you have a id and email in your state. Or define your state with user: {is: '', email:''} or do a conditional render. Hope I understood your problem correctly!

React componentDid mount get Async image. if not done before changing page, how to cancel the request?

I am kinda new to react coming from an Angular background. recently I am building a page where I display cards that all need to fetch an image from the microsoft graph api. The return type of the call is a base64 string. I don't want to put this into redux because it will make my devtools unreadable.
Therefore I decided to make a async call in the componentDidMount lifecycle hook with the this.isMounted pattern (Cancel All Subscriptions and Asyncs in the componentWillUnmount Method, how?). The problem however is that for some reason this doesn't unsubscribe the async call that I made. I am not sure whether I made a mistake or whether it needs to be unsubscribed instead of checking whether the component is mounted. but I cannot find any information on how to deal with this.
Any help would be appreciated.
My teamCard code:
import React from "react";
import { Icon } from "office-ui-fabric-react/lib/Icon";
import TeamCardLogo from "./teamCardLogo/teamCardLogo";
import TeamCardPersona from "./teamCardPersona/teamCardPersona";
import { GetGroupMembers } from "../../HttpRepositories/graphRepository";
import { FormattedMessage } from "react-intl";
import Fade from "react-reveal/Fade";
import { Modal } from "office-ui-fabric-react/lib/Modal";
import reactAppInsights from "react-appinsights";
import TeamModal from "./teamModal/teamModal";
class TeamCard extends React.Component {
state = {
members: "",
modelIsOpen: false
};
async componentDidMount() {
let members = await GetGroupMembers(this.props.id);
if (this.state.member !== "error") {
this.setState({ members });
}
}
_openModal = id => {
this.setState({ modelIsOpen: true });
};
_closeModal = () => {
this.setState({ modelIsOpen: false });
};
render() {
let members = "";
if (
typeof this.state.members !== "undefined" &&
this.state.members.length > 0 &&
this.state.members !== "error"
) {
members = this.state.members.map((member, i) => {
if (i < 5) {
return (
<div className="team-card-body__personas-wrapper-person" key={i}>
<TeamCardPersona
className="team-card-body__personas-wrapper-person"
member={member}
key={i}
/>
</div>
);
}
});
} else {
members = <div className="no-members-spacer" />;
}
let favouriteIcon = "";
this.props.isFavorite === true
? (favouriteIcon = <Icon iconName="FavoriteStarFill" />)
: (favouriteIcon = <Icon iconName="FavoriteStar" />);
return (
<React.Fragment>
{/* <Fade bottom delay={this.props.delay} appear={true}> */}
<article
className="team-card-wrapper"
onClick={() => this._openModal(this.props.id)}
>
<header className="team-card-wrapper__header">
<TeamCardLogo
injectClass="team-card-wrapper__header-photo"
teamId={this.props.id}
/>
<div className="team-card-wrapper__header-options-wrapper">
<div className="header-options__icon-group">
<div className="header-options__group-type">
<Icon iconName="LockSolid" />
</div>
</div>
<div className="header-options__icon-group">
<div className="header-options__favourite">{favouriteIcon}</div>
</div>
</div>
</header>
<section className="team-card-body">
<h1>{this.props.title}</h1>
<h2>
{" "}
<FormattedMessage
id="teamcard.memberCount"
defaultMessage="Leden"
/>
:{this.state.members.length}
</h2>
<div className="team-card-body__personas-wrapper">{members}</div>
<p className="description">{this.props.description}</p>
{/* <div className="team-card-body__join-button-wrapper">
<PrimaryButton text="Lid worden" />
</div> */}
</section>
</article>
{/* </Fade> */}
<Modal
titleAriaId={this._titleId}
subtitleAriaId={this._subtitleId}
isOpen={this.state.modelIsOpen}
onDismiss={this._closeModal}
isBlocking={false}
containerClassName="team-modal-wrapper"
>
<TeamModal
teamId={this.props.id}
title={this.props.title}
description={this.props.description}
favorite={this.props.isFavorite}
members={this.state.members}
closeModal={this._closeModal}
/>
</Modal>
</React.Fragment>
);
}
}
export default TeamCard;
my TeamCardLogo code (makes the async call)
import React from "react";
import { Icon } from "office-ui-fabric-react/lib/Icon";
import { getImage } from "../../../HttpRepositories/graphRepository";
class TeamCardImage extends React.Component {
constructor(props) {
super(props);
this._isMounted = false;
}
state = {
groupImage: ""
};
getLogo = () => {};
async componentDidMount() {
this._isMounted = true;
if (this._isMounted) {
let logo = await getImage(
`https://graph.microsoft.com/v1.0/groups/${
this.props.teamId
}/photo/$value`
);
if (logo !== "error") {
this.setState({ groupImage: logo });
}
}
}
render() {
let injectedClassName =
this.props.injectClass != "" ? this.props.injectClass : "";
let headerPhoto = "";
const groupIcon = (
<div className="team-card-wrapper__header-photo-alt">
<Icon iconName="Group" />
</div>
);
if (this.state.groupImage === "") {
headerPhoto = groupIcon;
} else {
headerPhoto = <img src={this.state.groupImage} alt=" " />;
}
return (
<React.Fragment>
<div className={injectedClassName}>{headerPhoto}</div>
</React.Fragment>
);
}
componentWillUnmount() {
this._isMounted = false;
}
}
export default TeamCardImage;
my httpRepos code
import { getGraphToken } from "../adalConfig";
import axios from "axios";
export const GetGroupMembers = async groupId => {
// we initiate a new token, to be sure that it didn't expire.
let graphToken = getGraphToken();
try {
let response = await axios({
url: `https://graph.microsoft.com/v1.0/groups/${groupId}/members?$select=id,displayName`,
method: "GET",
headers: { Authorization: "Bearer " + graphToken }
});
if (response.status != 200 && response.status != 204) {
return "error";
}
return await response.data.value;
} catch (error) {
return "error";
}
};
export const getImage = async url => {
// we initiate a new token, to be sure that it didn't expire.
let graphToken = getGraphToken();
try {
let response = await axios({
url: url,
method: "get",
responseType: "blob",
headers: { Authorization: "Bearer " + graphToken }
});
if (response.status != 200 && response.status != 204) {
return "error";
}
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL(response.data);
return await imageUrl;
} catch (error) {
return "error";
}
};
You want to check that _isMounted is still true before you call setState, not before you start the request.
async componentDidMount() {
this._isMounted = true;
let logo = await getImage(
`https://graph.microsoft.com/v1.0/groups/${this.props.teamId}/photo/$value`
);
if (this._isMounted && logo !== "error") {
this.setState({ groupImage: logo });
}
}

React + axios async call

I am using axios to fetch some data on the componentDidMount lifecycle method. The call was originally in the same file and thus i could update this.setState({members}). however I wanted to abstract the logic into a serperate file to keep the code clean.
I split the logic into a new file and start using the axios async await pattern. hoewever it seems like React doesn't wait for my axios call to finish. I went throught the docs and several posts but I cannot seem to find the problem. any hints are appreciated!
PS: I used create react app as base and added the dns mock:
https://github.com/hapijs/isemail/issues/26
Teamcard file
import React from "react";
import { Icon } from "office-ui-fabric-react/lib/Icon";
import { PrimaryButton } from "office-ui-fabric-react/lib/Button";
import TeamCardLogo from "./teamCardLogo/teamCardLogo";
import TeamCardPersona from "./teamCardPersona/teamCardPersona";
import { GetGroupMembers } from "../../HttpRepositories/graphRepository";
class TeamCard extends React.Component {
state = {
members: ""
};
componentDidMount() {
let members = GetGroupMembers(this.props.id, 5);
console.log("members", members);
this.setState({ members });
}
render() {
let members = "";
if (
typeof this.state.members !== "undefined" &&
this.state.members.length > 0
) {
members = this.state.members.map((member, i) => {
return (
<div className="team-card-body__personas-wrapper-person" key={i}>
<TeamCardPersona
className="team-card-body__personas-wrapper-person"
member={member}
key={i}
/>
</div>
);
});
}
let favouriteIcon = "";
this.props.isFavorite === true
? (favouriteIcon = <Icon iconName="FavoriteStarFill" />)
: (favouriteIcon = <Icon iconName="FavoriteStar" />);
return (
<article className="team-card-wrapper">
<header className="team-card-wrapper__header">
<TeamCardLogo
className="team-card-wrapper__header-photo"
teamId={this.props.id}
/>
<div className="team-card-wrapper__header-options-wrapper">
<div className="header-options__icon-group">
<div className="header-options__group-type">
<Icon iconName="LockSolid" />
</div>
</div>
<div className="header-options__icon-group">
<div className="header-options__favourite">{favouriteIcon}</div>
</div>
</div>
</header>
<section className="team-card-body">
<h1>{this.props.title}</h1>
<h2>Leden: {this.props.memberCount}</h2>
<div className="team-card-body__personas-wrapper">{members}</div>
<p className="description">{this.props.description}</p>
<div className="team-card-body__join-button-wrapper">
<PrimaryButton text="Lid worden" />
</div>
</section>
</article>
);
}
}
export default TeamCard;
seperated get request file:
import { getGraphToken } from "../adalConfig";
import axios from "axios";
import { resolve } from "dns";
export async function GetGroupMembers(groupId, numberOfMembers) {
// we initiate a new token, to be sure that it didn't expire.
let graphToken = getGraphToken();
let response = await axios({
url: `https://graph.microsoft.com/v1.0/groups/${groupId}/members?$top=${numberOfMembers}`,
method: "GET",
headers: { Authorization: "Bearer " + graphToken }
});
if (response.status != 200 && response.status != 204) {
console.log("error");
}
console.log("returning data", response.data.value);
return response.data.value;
}
Screenshot of logging:
You are missing an await here: let members = await GetGroupMembers(this.props.id, 5); and componentDidMountmust be declared async.

React HighChart Example

I m using React-js-highcharts, and i have done the below code, getting data e.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
error.
Kindly help me to sort out this.
Have followed this example.
https://github.com/whawker/react-jsx-highcharts/blob/gh-pages/examples/SimpleLine/App.js
import React from 'react';
import Highcharts from 'highcharts';
import {
HighchartsChart, Chart, withHighcharts, XAxis, YAxis, Title, Subtitle, Legend, LineSeries
} from 'react-jsx-highcharts';
import { extent as d3ArrayExtent } from 'd3-array';
const plotOptions = {
series: {
pointStart: 2010
}
};
class ProductHealth extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
}
}
componentDidMount() {
let defaultOptions = {
method:'GET',
headers:{
Accept: 'application/json',
}
};
fetch('http://localhost:3000/health', defaultOptions)
.then(function(response) {
// The response is a Response instance.
// You parse the data into a useable format using `.json()`
let resData = response.json();
return resData;
}).then(response => {
console.log("Response",response);
this.processResponseData(response);
}).catch(function(error){ console.log(error) })
}
processResponseData = (response) => {
let apiValues = [];
response.forEach(element => {
let value = [];
element.values.forEach(item => {
value.push(
[item.count]
);
})
apiValues.push({
name : element.api,
value : value
})
});
this.setState({
data : apiValues
});
};
renderLineChart() {
return this.state.data.map((lineData, index) => {
return (
<LineSeries key={index} name={lineData.api} data={lineData.value} />
)
})
}
render() {
if (this.state.data.length > 0) {
return (
<div>
<HighchartsChart plotOptions={plotOptions}>
<Chart />
<Title>Visa Direct Data</Title>
<Legend layout="vertical" align="right" verticalAlign="middle" />
<XAxis>
<XAxis.Title>Time</XAxis.Title>
</XAxis>
<YAxis>
<YAxis.Title>API Calls</YAxis.Title>
{this.renderLineChart()}
</YAxis>
</HighchartsChart>
</div>
);
} else {
return <div>Loading...</div>;
}
}
}
export default withHighcharts(ProductHealth, Highcharts);
I strongly recommend you to try to use our official React wrapper which is also available to download through npm.
Here is the link to package: https://www.npmjs.com/package/highcharts-react-official
GitHub repository: https://github.com/highcharts/highcharts-react
I know I'm 7 months late to this, but looks like the clue lies in
You may have returned undefined, an array or some other invalid object
You are returning this.state.data.map which will return an array.
I would suggest you try
renderLineChart () {
const { data } = this.state
return (
<Fragment>
{data.map((lineData, index) => (
<LineSeries key={index} name={lineData.api} data={lineData.value} />
)}
</Fragment>
)
}

Resources