I'm trying to do nested conditionals to be rendered and one case would make me use .map()
renderClasses () {
if (!this.state.classes.length) {
console.log(this.state.userType)
if (this.state.userType) return(<div>Add Class</div>)
else return (<div>Join Class</div>)
} else {
return (<div>{
this.state.classes.map((class) => {
^ unexpected token here
<div>one class</div>
})
}</div>)
}
}
render() {
if (!this.state.isLogged) {
return <Redirect to='/' />
}
return (
<div>
{
this.renderClasses()
}
</div>
);
}
Am i missing something? i tried wrapping everything into one <div> or maybe I understood it wrong? Thank you in advance
you do not return anything:
this.state.classes.map((item) => {
<div>one class</div>
})
try to paste return statement
this.state.classes.map((item) => {
return <div>one class</div>
})
But the error is cause by class being a reserved keyword, try to name it like item.
If you use {} in map function you need to use return as well. If its just a single statement, just ignore {}. You can use this -
this.state.classes.map(class => <div>one class</div>)
You should try returning from the map like this:
renderClasses () {
if (!this.state.classes.length) {
console.log(this.state.userType)
if (this.state.userType) return(<div>Add Class</div>)
else return (<div>Join Class</div>)
} else {
return (<div>{
this.state.classes.map((class, index) => {
return (<div key={index}>one {class}</div>)
})
}</div>)
}
}
render() {
if (!this.state.isLogged) {
return <Redirect to='/' />
}
return (
<div>
{
this.renderClasses()
}
</div>
);
}
Related
I've got a list of products to render. I also have an array of keywords that are used to exclude products from being rendered.
I am looping over the array of keywords and checking if the product title contains any of the entries. It then returns a boolean.
The following code does not work. The console.log works and reflects the result but nothing is rendered.
function inExcludes(product, excludedItems) {
excludedItems.forEach( item => {
if (product.includes(item)) {
console.log(true);
return true;
} else {
console.log(false);
return false;
}
})
}
export function CardsFiltered(props) {
const cards = props.items.map((product) => {
if (inExcludes(product.title, props.excludedItems) === false)
return (
<CardValidation
key={product.id}
id={product.id}
product={product}
/>
)
})
return (
<>
{cards}
</>
);
}
But if I set a variable as a boolean, switch that variable if the condition is true, and then return that variable, it works and my cards are rendered (code below).
Is anyone able to shed light on this? Because I can't figure it out.
function inExcludes(product, excludedItems) {
let result = false;
excludedItems.forEach( item => {
if (product.includes(item)) {
result = true;
}
})
return result;
}
export function CardsFiltered(props) {
const cards = props.items.map((product) => {
if (!inExcludes(product.title, props.excludedItems))
return (
<CardValidation
key={product.id}
id={product.id}
product={product}
/>
)
})
return (
<>
{cards}
</>
);
}
Your first implementation of 'inExcludes' isn't returning a boolean (true/false). It's just executing the 'forEach' on each item in the excludedItems array. The return within that loop doesn't return from the function as a whole.
So, as it effectively returns 'undefined' your render decides not to render anything.
Here's something that does what you're after (simplified a bit):
https://codesandbox.io/s/awesome-mcclintock-hkkhsi?file=/src/App.js
I'm trying to do conditional rendering in React (only maps and renders when props exist).
render() {
if (this.props.res) {
return(
<div>{this.props.res.map(item => <li key={item.id}>{item.subreddit}</li>}</div>
)
} else {
return null
}
}
But I have this error:
Parsing error: Unexpected token, expected ","
Why is that, and how can I fix it? Or in another way, is there a better way to achieve my purpose?
There is syntax error, map(...) doesn't have closing parenthesis.
It should be:
<div>{this.props.res.map(item => <li key={item.id}>{item.subreddit}</li>)}</div>
Here are the issues I see:
map is missing the closing parenthesis
check the array length (an empty array will return true otherwise)
list items should be wrapped with an appropriate tag, such as <ul/>
render() {
const { res } = this.props;
return !res.length ? null : (
<ul>{res.map(item => <li key={item.id}>{item.subreddit}</li>)}</ul>
);
}
there was a brace missing in the end of the map.
render() {
return (
<div>
{
this.props.res && this.props.res.map(item => (
<li key={item.id}>{item.subreddit}</li>
))
}
</div>
);
}
render() {
if (this.props.res) {
return (
<div>
{this.props.res.map(item => (
<li key={item.id}>{item.subreddit}</li>
))}
</div>
);
} else {
return null;
}
}
I would like to simplify "renderTitle" and "renderComments" in a unique function in a React component:
renderTitle(dish) {
return (
<h2>
Title array comment
</h2>
);
}
renderComments(dish) {
return (
dish.array.map(comment => {
return (
<div>
hello
</div>
);
})
);
}
render() {
return (
{this.renderTitle(this.props.dish)}
{this.renderComments(this.props.dish)}
);
}
Take a look at below code where I used Fragment (react 16.x). And see how I merged the functions in your question.
renderItems(dish) {
const comments = dish.array.map(comment => (<div>hello</div>))
return (
<React.Fragment>
<h2>
Title array comment
</h2>
{comments}
</React.Fragment>
);}
To use regular JavaScript expressions in the middle of JSX you have to wrap the JavaScript expression in {}.
Note that to return multiple elements on the same level you should either return an array or wrap them in a Fragment:
render() {
return (
<React.Fragment>
<h2>
Title array comment
</h2>
{
dish.array.map(comment => (
<div>
hello
</div>
));
}
</React.Fragment>
);
}
You can do this if this.props.dish is array.
renderTitle(dish) {
return dish.map(i => {
return <div>{i.title}</div>;/*this title may change*/
});
}
renderComments(dish) {
return dish.map(i => {
return <div>{i.comment}</div>;/*this comment may change*/
});
}
render() {
return (
<div>
{this.renderTitle(this.props.dish)}
{this.renderComments(this.props.dish)}
</div>
);
}
Have been facing issue while iterating through a list and printing elements in React.
The React Code is:
import React from 'react';
import ReactDOM from 'react-dom';
class NewComponent extends React.Component {
constructor(props){
super(props);
this.state = {myData: []}
}
componentWillMount(){
let data = document.getElementById('demo').innerHTML;
data = JSON.parse(data);
this.setState({myData: data});
}
render() {
return this.state.myData.map((item) => {
return (
<div>
<h3>{item.title}</h3>
<p>{item.description}</p>
</div>
);
});
}
}
ReactDOM.render(
<NewComponent />,
document.getElementById('demo')
)
And I'm getting an error of:
bundle.js:830 Uncaught Error: NewComponent.render(): A valid React element
(or null) must be returned. You may have returned undefined, an array or
some other invalid object.
I'm pretty sure there is some issue with returns in the render function of the
Not sure what is the issue though.
EDITS
I have made the following edits, the error is not there anymore but nothing is rendering.
renderList() {
console.log("Running");
return this.state.myData.map((item) => {
<div>
<h3>{item.title}</h3>
<p>{item.description}</p>
</div>
});
}
render() {
console.log(this.state.myData);
if(this.state.myData.length)
return <div>{this.renderList()}</div>
else
return <div>Loading...</div>
}
In Chrome console I'm getting:
(2) [{…}, {…}]
0:{_id: {…}, description: "hello", title: "sankit"}
1:{_id: {…}, description: "lets add some thing new", title: "hi"}
length:2
_proto_:Array(0)
Running
what you can do is extract your js code from the render method in a separate method like so:
renderList() {
return this.state.myData.map((item) => {
<div>
<h3>{item.title}</h3>
<p>{item.description}</p>
</div>
})
}
then in your render method:
render() {
if(this.state.myData.length){
return (
<div>{this.renderList()}</div>
);
}
else
{
return (
<div>Loading...</div>
);
}
}
You can wrap it with root element like div,
React ver 15 render functions supports only returning one element.
render() {
<div>{this.state.myData.map((item) =>
<div>
<h3>{item.title}</h3>
<p>{item.description}</p>
</div>
)}</div>
}
}
Change like this, While you using map should use key attribute for index
makeUI() {
if(!this.state.myData.length)
return
return this.state.myData.map((item, index) => {
return (
<div key={index}>
<h3>{item.title}</h3>
<p>{item.description}</p>
</div>
)
})
}
render() {
return (<div>
{ this.makeUI() }
</div>
)
}
I think you are missing the return in renderList -> .map
This should work.
renderList() {
return this.state.myData.map((item) => {
return (
<div>
<h3>{item.title}</h3>
<p>{item.description}</p>
</div>
);
});
}
render() {
if(this.state.myData.length){
return (
<div>{this.renderList()}</div>
);
}
else {
return (
<div>Loading...</div>
);
}
}
in many of my components I am fetching API data and therefor I need to wait until that data was loaded. Otherwise I am getting errors because some methods are, of course, not available.
My api query looks like this
componentDidMount() {
prismicApi(prismicEndpoint).then((api) =>
api.form('everything')
.ref(api.master())
.query(Prismic.Predicates.at("my.page.uid", this.props.params.uid))
.submit((err, res) => {
if (res.results.length > 0) {
this.setState({doc: res.results[0]});
} else {
this.setState({notFound: true});
}
}))
}
For that I've created this structure that I have been using in all of these documents:
render() {
if (this.state.notFound) {
return (<Error404 />);
} else if (this.state.doc == null || !this.state.doc) {
return (<Loading />);
} else {
return (
<div className="page">
{this.state.doc.getSliceZone('page.body').slices.map(function(slice, i){
return (<SliceZone slice={slice} key={i} />)
})}
</div>
)
}
}
I wanted to move this into a component called Document that looks like this here:
export default class Document extends React.Component {
static defaultProps = {
doc: null,
notFound: false
}
static propTypes = {
doc: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]),
notFound: React.PropTypes.bool.isRequired
}
render() {
if (this.props.notFound) {
return (<Error404 />);
} else if (this.props.doc == null || !this.props.doc) {
return (<Loading />);
} else {
return (
<div className="page">
{this.props.children}
</div>
)
}
}
}
and then I tried to use it like this here:
<Document doc={this.state.doc} notFound={this.state.notFound}>
{this.state.doc.getSliceZone('page.body').slices.map(function(slice, i){
return (<SliceZone slice={slice} key={i} />)
})}
</Document>
Though on the second example the error messages are showing up quickly (until the data is loaded) and then disappear. What am I doing wrong? Why is the first example working and the second doesnt?
try this
<Document doc={this.state.doc} notFound={this.state.notFound}>
{ this.state.doc && this.state.doc.getSliceZone('page.body').slices.map(function(slice, i){
return (<SliceZone slice={slice} key={i} />)
})}
</Document>
in your variant, you see an error becuase this.state.doc is null, untill data is loaded, and you see null reference exception, looks like.
In 1st case, it does not calculate, in 2nd case it calculates first and then sent as a parameter "children" to your Document control