Failed to compile, Unexpected token if in ReactJS - reactjs

I cant seem to get this simple function to work basically my markup is like so(simplified)
{ loading || Object.keys(product).length <= 0 ? 'loading' :
<div>
{if(){
}}
<ProductPictureWidget mainPic={product.pic_url} />
<ProductOptionsWidget product={product} activeProps={activeProps} selectProductOption={this.selectProductOption}/>
</div>
}
But this leaves me with SyntaxError: Unexpected token on my if statement
What exactly am I doing wrong here am I not allowed to do if statements within my shorthand if statement?

JSX only allows expressions, not statements. The ternary operator is an expression. if starts an if statement. You can see why an if statement wouldn't work by looking at the compiled JavaScript (with the if statement removed):
{
loading || Object.keys(product).length <= 0 ? 'loading' : React.createElement(
'div',
null,
React.createElement(ProductPictureWidget, { mainPic: product.pic_url }),
React.createElement(ProductOptionsWidget, { product: product, activeProps: activeProps, selectProductOption: undefined.selectProductOption })
);
}
JSX amounts to function calls and object declarations. If the if statement were compiled, it would yield invalid JavaScript:
{
loading || Object.keys(product).length <= 0 ? 'loading' : React.createElement(
'div',
null,
if(){ }, // This is **invalid** JavaScript!!
React.createElement(ProductPictureWidget, { mainPic: product.pic_url }),
React.createElement(ProductOptionsWidget, { product: product, activeProps: activeProps, selectProductOption: undefined.selectProductOption })
);
}

JSX doesn't allow if statement within the return function. But you are allowed to use ternary expressions
{ loading || Object.keys(product).length <= 0 ? 'loading' :
<div>
{(condition here)? <div>Hello World</div>: null}
<ProductPictureWidget mainPic={product.pic_url} />
<ProductOptionsWidget product={product} activeProps={activeProps} selectProductOption={this.selectProductOption}/>
</div>
}
However if you want to make use of if statement there is an alternative way to do it, i.e to call a function within which you use the if-else statements
conditionalRender() {
if(condition) {
return <div>Hello</div>
} else {
return null
}
}
{ loading || Object.keys(product).length <= 0 ? 'loading' :
<div>
{this.conditionalRender()}
<ProductPictureWidget mainPic={product.pic_url} />
<ProductOptionsWidget product={product} activeProps={activeProps} selectProductOption={this.selectProductOption}/>
</div>
}

Related

Expression in JSX Return gives "Unexpected token, expected "," "

It's something simple I'm missing. My component takes the props userInfo={..} small={true}. I am getting the error
requestorEligibilitySection.js: Unexpected token, expected "," (10:14)
on Line 10 which is the overall content constraint
{props.userInfo ?
on the period, which is highlighted as the error with the expected comma.
export default function RequestorEligibilitySection(props) {
// Return JSX
// ----------
return (
{props.userInfo ?
<>
{props.small
?
<h3>
{props.userInfo.organizationalstat === 'EMPLOYEE' ? 'Employee' : 'Trainee'} Eligibility
</h3>
:
<h2>
{props.userInfo.organizationalstat === 'EMPLOYEE' ? 'Employee' : 'Trainee'} Eligibility
</h2>
}
<p>Some text</p>
</>
: ''
}
);
}
I also tried with {props.userInfo && .. } around the content and it's the same error on the period. I only have 1 child, <>..</>.
You have an extra scope {props.userInfo} in your return expression, it expects an object definition:
export default function RequestorEligibilitySection(props) {
...
// Not {props.userInfo ...}, remove extra {}
return props.userInfo ? ...;
}
Without deleting anything, you can add a React.Fragment wrapper or any element so you can return a single React.Node:
export default function RequestorEligibilitySection(props) {
...
// Add a wrapper
return (
<>
{props.userInfo ?
...
}
</>
);
}

How to pass if condition loop output to a variable in reactjs

I need help to solve this
let someVar
render(
{
this.props.someData.map((items) =>
items.someotherData.map((item) =>
(item.data1 > 5 && item.data2 == "more") ? classNames({ "classname1": true })
: (item.data1 > 5 && item.data2 == "less") ? classNames({ "classname2": true })
: classNames({ "classname3": true })
))
}
<div className = { someVar } ></div>
)
I need my output of if loop to be pass to the variable
I tried many method. Nothing worked. Please give the solution
render() {
let someVar
this.props.someData.forEach(items =>
items.someotherData.forEach(item =>
item.data1 > 5 && item.data2 == 'more'
? someVar = 'classname1'
: item.data1 > 5 && item.data2 == 'less'
? someVar = 'classname2'
: someVar = 'classname3'
)
)
return <div className={someVar}></div>
}
I didn't really get what you were trying to do. Are you calling some function with the class names or something? Here is my best try to solve your problem though.
First we create the variable,
Then we do data processing. You shouldn't use map but instead the forEach if you are not returning anything. You are also overwriting the variable for each item (is this preferred behaviour?).
Then we actually return the React part of the code. Render function always needs to return JSX or null. Inside JSX we can use the someVar in the className. The final value of className needs to be a string. That's why we are putting strings to the someVar.

ternary operator not working in map function react

I am mapping through an array of objects, some of the images are broken so I created a function to check the image which returns true or false and if false then use a placeholder image.
However I am getting an error and I think its because I am using a ternary operator inside the map function. Any ideas?
Function:
public renderProfile() {
// Grabs the array of objects
const profiles = this.state.profiles;
// Renders the selected profile
const renderProfiles = profiles.splice(0, this.props.postCount).map(profile => (
this.checkImageUrl(profile.imgUrl) ? profile.imgUrl : profile.imgUrl = 'https://via.placeholder.com/300x167.png?text=LINKEDIN';
<div key={shortid.generate()} className={styles.linkedInContainer}>
<DocumentCard
aria-label={profile.postContent}
onClickHref={profile.postUrl}
> { profile.imgUrl &&
<img className={styles.linkedInHeroImage } src={ profile.imgUrl } />
}
<DocumentCardTitle
title={profile.postContent}
shouldTruncate={true}
/>
<DocumentCardActivity
activity={`Likes: ${profile.likeCount}`}
people={[{ name: 'Read more on linkedIn', profileImageSrc: profile.imgUrl ? profile.imgUrl : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAA' }]}
/>
</DocumentCard>
</div>
));
return renderProfiles;
}
This is braking it:
this.checkImageUrl(profile.imgUrl) ? profile.imgUrl : profile.imgUrl = 'https://via.placeholder.com/300x167.png?text=LINKEDIN';
[15:43:22] Error - [tsc] src/webparts/linkedIn/components/LinkedIn.tsx(143,157): error TS1005: ')' expected.
[15:43:22] Error - [tsc] src/webparts/linkedIn/components/LinkedIn.tsx(163,5): error TS1128: Declaration or statement expected.
[15:43:22] Error - [tsc] src/webparts/linkedIn/components/LinkedIn.tsx(163,6): error TS1128: Declaration or statement expected.
Check image function:
// Checks linkedIn images for broken ones
private checkImageUrl(url) {
var lastPart = url.substr(url.lastIndexOf('=') + 1);
if (lastPart === "image") {
return true;
} else {
return false;
}
}
https://codepen.io/bkdigital/pen/poojmbo?editors=1011 - This proves the check url function is working
On this line,
const renderProfiles = profiles.splice(0, this.props.postCount).map(profile => (
You start the function passed to .map() with a (.
JavaScript will interpret anything that comes after it as the return value of the function.
Since your function has another statement inside of it, this will cause an error.
You should change it as follow:
const renderProfiles = profiles.splice(0, this.props.postCount).map(profile => {
this.checkImageUrl(profile.imgUrl) ? profile.imgUrl : selectedProfile.imgUrl = 'https://via.placeholder.com/300x167.png?text=LINKEDIN';
return (
<div key={shortid.generate()} className={styles.linkedInContainer}>
<DocumentCard
aria-label={profile.postContent}
onClickHref={profile.postUrl}
> { profile.imgUrl &&
<img className={styles.linkedInHeroImage } src={ profile.imgUrl } />
}
<DocumentCardTitle
title={profile.postContent}
shouldTruncate={true}
/>
<DocumentCardActivity
activity={`Likes: ${profile.likeCount}`}
people={[{ name: 'Read more on linkedIn', profileImageSrc: profile.imgUrl ? profile.imgUrl : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAA' }]}
/>
</DocumentCard>
</div>
);
});

How to display react numerical props only if they pass from the container?

I have two different containers that call ControlSection component. One pass bestScore prop and the second pass level prop.
In the ControlSection component I want to display the prop in <h2> only if they pass from the container. How can I do it?
const ControlSection = ({ score, bestScore, level }) => {
return (
<div className='controlSection'>
<div className='gameStatistics'>
<h2>Score: {score}</h2>
{bestScore ? <h2>Best: {bestScore}</h2>}
{level ? <h2>Level: {level}</h2>}
</div>
</div>
)
}
The term you're looking for is Conditional Rendering and the standard way to render a component when the prop is defined is by using the && operator.
{bestScore && <h2>Best: {bestScore}</h2>}
The second part, <h2>Best: {bestScore}</h2>, will only be rendered if bestScore is true. (you could use any other condition here)
This is because in JS, undefined, null, 0, '' and NaN are evaluated as false (falsy).
false && <h1>something</h1> will be evaluated as false, therefore it won't be rendered.
Coming back to the bestScore prop, it could also be 0 and evaluated as falsy. You need to take care of that. Something like this could work:
{(bestScore || bestScore === 0) && <h2>Best: {bestScore}</h2>}
What I would do in your case is the following to cover your requirement:
const ControlSection = ({ score, bestScore, level }) => {
return (
<div className='controlSection'>
<div className='gameStatistics'>
<h2>Score: {score}</h2>
{bestScore != null ? <h2>Best: {bestScore}</h2> : null}
{level != null ? <h2>Level: {level}</h2> : null}
</div>
</div>
)
}
By doing bestScore != null the code identifies 2 different things as false which are null and undefined. Please refer to the following code example:
let bestScore = null;
console.log('testing for null value:', bestScore != null);
bestScore = undefined;
console.log('testing for undefined value:', bestScore != null);
bestScore = '';
console.log('testing for \'\' value:', bestScore != null);
bestScore = 0;
console.log('testing for 0 value:', bestScore != null);
In false value case the h2 tag won't be rendered in your component thus you have covered 2 cases where you have either undefined or null value from properties.
To handle 0 and '' values you might want to do the following:
function hasToRender(value) {
if (value === '') {
return false;
} else if (value == 0) {
return true;
} else if (value != null) {
return true;
}
return false;
}
console.log('null', hasToRender(null));
console.log('undefined', hasToRender(undefined));
console.log('\'\'', hasToRender(''));
console.log(0, hasToRender(0));
console.log(17, hasToRender(17));
So I think the working solution would be the following in your case to cover all the cases:
const ControlSection = ({ score, bestScore, level }) => {
function hasToRender(value) {
if (value === '') {
return false;
} else if (value == 0) {
return true;
} else if (value != null) {
return true;
}
return false;
}
return (
<div className='controlSection'>
<div className='gameStatistics'>
<h2>Score: {score}</h2>
{hasToRender(bestScore) ? <h2>Best: {bestScore}</h2> : null}
{hasToRender(level) ? <h2>Level: {level}</h2> : null}
</div>
</div>
)
}
Of course the hasToRender function can be simplified further but this gives you the idea, hope this helps!
{typeof bestScore !== 'undefined' && <h2>Best: {bestScore}</h2>}
or
{typeof level === 'number' && <h2>Level: {level}</h2>}

Convert working VueJS component to ReactJS

I have a Vue component that works just fine. Now I'm trying to convert that code to ReactJS equivalent. My attempt on React
var ticksArray = Array.apply(null, {length: 27}).map(Number.call, Number);
export default class Timer extends Component {
constructor(props) {
super(props);
this.state = {
angle:250,
minangle:0,
maxangle:270,
xDirection:"",
yDirection:"",
oldX:0,
dragging: false
}
}
onMousedown(){
this.setState({dragging : true});
}
onMouseup(){
this.setState({dragging : false});
}
onMousemove(e){
if(!this.state.dragging)
return;
this.setState({
xDirection : this.state.oldX < e.pageX ? 'right' : 'left',
oldX:e.pageX,
yDirection: this.state.xDirection === 'left' ? 'down' : 'up'
});
if(this.state.yDirection === 'up' && this.state.angle + 2 <=
this.state.maxangle)
this.setState({angle:this.state.angle += 2})
else if(this.state.yDirection === 'down' && this.state.angle - 2 >=
this.state.minangle)
this.setState({angle:this.state.angle -= 2})
}
knobStyle(){
return {
'transform':'rotate('+this.state.angle+'deg)'
}
}
activeTicks(){
return (Math.round(this.state.angle / 10) + 1);
}
currentValue(){
return Math.round((this.state.angle/270)*100) + '%'
}
componentDidMount(){
document.addEventListener('mouseup',this.state.onMouseup)
document.addEventListener('mousemove',this.state.onMousemove)
}
render() {
var tickDivs = ticksArray.map(function(item) {
return (
<div key={item} className="tick"></div>
);
});
return (
<div id="timer">
<div className="knob-surround">
<div className="knob"></div>
<span className="min">Min</span>
<span className="max">Max</span>
<div className="ticks" className="n <= activeTicks ?
'activetick' : ''">
{tickDivs}
</div>
</div>
</div>
);
}
}
It's not working. I'm missing something. I'm assuming the problem lies in this code bit.
<div className="ticks" className="n <= activeTicks ?
'activetick' : ''">
Please help fix this.
Add this here instead of comment:
React uses the following syntax:
className={n <= activeTicks ? 'activetick' : ''}
In componentDidMount you assign handlers in a wrong way, should be like:
document.addEventListener('mouseup', this.onMouseup)
Note here that handler is not a part of your state. And the corresponding definition of the handler:
private onMouseup = () => {...}
The reason to store reference for the event handler instead of having class method - see in #3
Do not forget to unsubscribe your event handlers in componentWillUnmount like this:
window.removeEventListener("mouseup", this.onMouseup);
UPDATE:
Here is an example working without using arrow functions: https://jsfiddle.net/6dnrLw4n/4/

Resources