why would react not render conditionally - javascript

So i have an issue while trying to render this list, item.cars, item.yachts and item.villas are numbers, what could be the reason for this not showing absolutely anything?
const renderItems = (locations) => {
<div className={styles.list}>
{locations.map((item) => {
if (item.cars != 0 || item.yachts != 0 || item.villas != 0)
return (
<DestinationItem
id={item.id}
image={Image[item.id]}
name={item.name}
subtitle={item.description}
description={DESTINATIONS_DESCRIPTION[item.id]}
/>
);
return null;
})}
</div>;
};
this is an item in locations object
cars: 0
description: "(Miami, Palm Beach, Broward)"
id: 3
name: "South Florida"
photo: "http://l.amazonaws.com/areaphotos/Audi_R8_a.jpg"
villas: 69
yachts: 53
__proto__: Object
this is the whole component code:
const Destinations = locations => {
const renderItems = (locations) => {
<div className={styles.list}>
{locations.map(
(item) =>
(item.cars != 0 || item.yachts != 0 || item.villas != 0) && (
<DestinationItem
id={item.id}
key={item.id}
image={Image[item.id]}
name={item.name}
subtitle={item.description}
description={DESTINATIONS_DESCRIPTION[item.id]}
/>
)
)}
</div>;
console.log(locations, 'data');
return (
<div className={styles.mainContainer}>
<div className={styles.title}>
<h1>Pick Your Destination</h1>
</div>
{renderItems(locations)}
</div>
);
};
};
export default Destinations;

Ok, so I'm not fully sure, but I try not to use if statements in the DOM. Try this style of conditional instead:
<div className={styles.list}>
{locations.map((item) =>
(item.cars != 0 || item.yachts != 0 || item.villas != 0) && (
<DestinationItem
id={item.id}
key={item.id}
image={Image[item.id]}
name={item.name}
subtitle={item.description}
description={DESTINATIONS_DESCRIPTION[item.id]}
/>)
})
</div>;
The && operator acts as your if statement. And this way, you don't even need to include {}s in your map function. Also, don't forget to add a unique key to any mapped elements!

The Destinations component takes locations as a prop, correct? In that case, you'll want to either destructure the props object, like this:
const Destinations = ({ locations }) => {
or this
const Destinations = props => {
const { locations } = props
or just use the props object and access the fields separately:
const Destinations = props => {
// ...
return (
// ...
{renderItems(props.locations)}
// ...
)
}
Additionally, the renderItems function has curly braces around it, so you need to use return to return a value from it. It's currently returning undefined, as there is no return.
const renderItems = (locations) => {
return (
<div className={styles.list}>
{locations.map((item) => {
if (item.cars !== 0 || item.yachts !== 0 || item.villas !== 0)
return (
<DestinationItem
id={item.id}
image={Image[item.id]}
name={item.name}
subtitle={item.description}
description={DESTINATIONS_DESCRIPTION[item.id]}
/>
);
return null;
})}
</div>
);
};
Or you can use the concise form of an arrow function, and replace the curly braces with parentheses:
const renderItems = (locations) => (
<div className={styles.list}>
{locations.map((item) => {
if (item.cars !== 0 || item.yachts !== 0 || item.villas !== 0)
return (
<DestinationItem
id={item.id}
image={Image[item.id]}
name={item.name}
subtitle={item.description}
description={DESTINATIONS_DESCRIPTION[item.id]}
/>
);
return null;
})}
</div>
);
As a side-note, you'll almost always want to use strict equality operators (=== and !==) instead of abstract equality operators (== and !=). The latter one has its share of pitfalls, e.g. '1' == 1 is true, as unexpected things like [[]] == 0!

Related

How to set value to state for recursive rendered component?

I need to make a component. This should be a editable tree component. I tried a lot, but i can't handle issue. I don't use any libraries such as redux. I made a component it travel all json object recusively. Now, At onChange event, it passes param (path of key) according to this path I wrote a function called 'updateObjectValueByPath' updates that value. Now I need to save this json object to a state. But I can't save latest version, when I switch input field 'datas' object reset its value. Here is my code, maybe I can't explain myself clearly. Hope code can help. Thanks for all..
render() {
let json = this.state.json;
const data = this.props.data;
const path = this.props.path;
if (Array.isArray(data)) {
return data.map((element, index) => {
let currentPath = `${path}.${index}`;
return (
<div key={index}>
<CCol sm={12}>
<CInputGroup>
<CCol sm={3}>
<CInputGroupPrepend>
<CListGroup accent>
<CListGroupItem key="id" accent="success">
{this.props.properties}
{index + 1} :
</CListGroupItem>
</CListGroup>
</CInputGroupPrepend>
</CCol>
<CCol sm={5}>
{index === 0 ? (
<CButton color="warning" onClick={() => this.addItem(path)}>
Add
</CButton>
) : null}
</CCol>
<CCol sm={4}>
<CButton
color="danger"
onClick={() => this.removeItem(path, index)}
>
Remove
</CButton>
</CCol>
</CInputGroup>
</CCol>
<CCol>
<JsonTree
path={currentPath}
data={element}
arrayIndex={index}
key={currentPath}
jsonContent={this.state.json}
></JsonTree>
</CCol>
</div>
);
});
} else if (data instanceof Object) {
// console.log(this.props.jsonContent);
return Object.keys(data).map((key) => {
let currentPath = path !== "" ? `${path}.${key}` : key;
return (
<JsonTree
data={data[key]}
path={currentPath}
key={currentPath}
properties={key}
jsonContent={this.state.json}
/>
);
});
} else {
// console.log(this.props.jsonContent);
return (
<div>
{console.log(this.state.json)}
{/* {this.setState({ json: this.state.den })} */}
<CCol sm={12} key={path}>
<CInputGroup>
<CCol sm={3}>
<CInputGroupPrepend>
<CListGroup accent>
<CListGroupItem key="id" accent="primary">
{this.props.properties}:
</CListGroupItem>
</CListGroup>
</CInputGroupPrepend>
</CCol>
<CCol sm={9}>
{/* number kabul edecek value olarak */}
{typeof data === "number" ? (
<CInput
id={path}
name={path}
defaultValue={data}
type="number"
style={{ fontWeight: "bold" }}
// disabled={!this.props.isEditable}
onChange={(event) => this.handleChange(event, path, json)}
/>
) : typeof data === "string" ? (
<CInput
id={path}
name={path}
type="text"
defaultValue={data}
style={{ fontWeight: "bold" }}
// disabled={!this.props.isEditable}
onChange={(event) => this.handleChange(event, path, json)}
/>
) : null}
</CCol>
</CInputGroup>
</CCol>
</div>
);
}
}
handleChange = (event, path, datas) => {
const seperatedPath = path.split(".");
let arrayPath = seperatedPath.map((v) => (isFinite(v) ? +v : v));
let value = event.target.value;
let newData = this.updateObjectValueByPath(arrayPath, datas, value);
console.log(newData);
this.setState({ json: newData });
};
updateObjectValueByPath = (arrayPath, datas, value) => {
const key = arrayPath[0];
if (Array.isArray(datas) && datas !== null) {
if (arrayPath.length > 1) {
return datas.map((el, index) => {
if (index === key) {
return this.updateObjectValueByPath(
arrayPath.slice(1, arrayPath.length),
el,
value
);
}
return el;
}, []);
}
return [...datas, value];
}
if (typeof datas === "object" && !Array.isArray(datas) && datas !== null) {
if (arrayPath.length > 1) {
return {
...datas,
[key]: this.updateObjectValueByPath(
arrayPath.slice(1, arrayPath.length),
datas[key],
value
),
};
}
return { ...datas, [key]: value };
}
return datas;
};
I solved that issue, for solution:
I wrote a callback function which call that class. And this callback prop also should be written in recursive field like that;
<JsonTree
data={data[key]}
path={currentPath}
key={currentPath}
properties={key}
jsonContent={this.state.json}
callback={this.props.callback}
/>
Then, when onchange event triggered, call this callback and sent newData as param.
let newData = this.updateObjectValueByPath({ arrayPath, datas, value });
console.log(newData);
this.props.callback(newData);
By doing this, we are traversing the new object as a parameter through the parent.

React Map Method within Map Method

I am trying to include map method in a map method while getting a list as an element from the first map method.
{columns &&
columns.map(column =>
column.list && column.list?
(column.list.map((item)=>{
return (
<CustomTableCell align="center">{item.name}
<span>{item.convertMethod(item.id, item.lists)}</span>
</CustomTableCell>
);
})):
<CustomTableCell align="center"> {column.name} </CustomTableCell>
) }
Error still exists
return (
<div className="App">
{
columns.map(column => {
return (
column.list && column.list.length > 0 ? (
column.list.map(item => {
return (
<div key={item.name}>{item.name}</div>
)
})
): ("")
)
})
}
</div>
);
demo

Render dynamically two image carousels on the same page

Update
I have an array of objects with data and one of the key is gallery, which is an array of URLs: data=[{id:1,gallery:[]},{id:2, galery:[]}].
I did an image carousel in the mapped "data" array. The problem is that the carousels, of each item, are not independent one of each other. Each time I change the picture on one of them, it changes to the other also.
Here is the code:
export class MyComponent extends Component {
state = {
current: 0,
currentItem: '',
}
render() {
const selecItem = (e) => {
this.setState({
currentItem: e.target.parentElement.parentElement.parentElement.id
})
}
const resetSelectedItem = ()=>{
this.setState({
currentItem: ''
})
}
const nextSlide = (e ,arr) => {
if (this.state.currentItem !==
e.target.parentElement
.parentElement.parentElement.id ) {
e.preventDefault()
} else if (arr &&
this.state.currentItem === e.target.parentElement
.parentElement.parentElement.id ) {
let copy = this.state.current
this.setState({
current: (copy === arr.length - 1 ? 0 : copy + 1),
})
}
}
const prevSlide = (e, arr) => {
if (this.state.currentItem !== e.target.parentElement
.parentElement.parentElement.id ) {
e.preventDefault()
} else if (arr &&
this.state.currentItem === e.target.parentElement
.parentElement.parentElement.id ) {
let copy = this.state.current
this.setState({
current: (copy === 0 ? arr.length - 1 : copy - 1),
})
}
}
return (
<section>
{data &&
data.map((item, i) =>
<>
<div key={i} id={i.toString().concat(item.id)}>
<div>
...some data here
</div>
<div>
<div>
...more data
</div>
<div className='carousel' onMouseEnter={(e)=>selecItem(e)}
onMouseLeave={resetSelectedItem}>
<img src={left}
className='left-arrow' alt="left"
onClick={(e) =>this.state.currentItem
=== i.toString().concat(data[i].id)
? prevSlide(e, data[i].gallery) : undefined} />
<img src={right}
className='right-arrow' alt="right"
onClick={(e) => this.state.currentItem
=== i.toString().concat(data[i].id)
? nextSlide(e, data[i].gallery) : undefined} />
{data[i].gallery?.map((img, j) => (
<>
{j === this.state.current && (
<img src={img} alt={item.id} className='cart-image' key={j} />
)}
</>
))}
</div>
</div>
</div>
</>)}
</section>)}}
export default MyComponent
I want to have a different carousel for each item from data array. For the moment it is working like a big one, instead of two.
For me it is strange that all the other data it is rendered the way I want.
I tried this one also:
{this.state.currentItem === i.toString().concat(data[i].id)?
data[i].gallery?.map((img, j) => (
<>
{j === this.state.current && (
<img src={img} alt={item.id} className='cart-image' key={j} />
)}
</>
))}
In this case it is displayed and active, the carousel for only one item from data. But I want both carousels to be visible and active one at a time
Could you please help me?
Thank you in advance
You only check for the index of the item in the gallery as condition to show the image. If the selected gallery-item is 0 for example, every first item of every gallery will be shown. You will also need to save the active item-index in a state, together with the active gallery-item-index (as you already do) and add it to the condition to show the image.
I did a new component, and I moved all the logic for the image carousel inside of this component.
Now everything it is working fine.
The code it is looking something like this now:
export class MyComponent extends Component {
render() {
return(
<section>
{data &&
data.map(item=>
<NewComponent
id={item.id}
gallery={item.gallery} />
)}
</section>
)
}
}

React Component inside .map() is throwing an error: TypeError: notes.map is not a function

am trying to show Noteitem component which is returned inside a map function.
{notes.map((note) => {
return (
<Noteitem key={note._id} updateNote={updateNote} showAlert={props.showAlert} note={note} />
);
})}
notes should be an array for map function to work. You can check it in following way if notes is not null and is an array using notes.length and apply map function
{notes && notes.length && notes.map((note) => {
return (
<Noteitem key={note._id} updateNote={updateNote} showAlert={props.showAlert} note={note} />
);
})}
You can put if/else statement inside JSX to check the variable whether is exist or not
return (
<>
{
notes.length
? 'fallback'
: notes.map(note => <Noteitem key={note._id} updateNote={updateNote} showAlert={props.showAlert} note={note} />)
}
</>
)
IIFE
{(() => {
if ("check note") {
// fallback
}
return notes.map((note: NoteProps) => (
<Noteitem key={note._id} updateNote={updateNote} showAlert={props.showAlert} note={note} />
));
})()}

How to properly destruct object within map function using javascript?

I would like to know how can i destruct object within .map function using javascript, i have react js component and within return method i have the code below:
return (
<>
{setItems.map(setItem => (
const { childContentfulPartFeatureSetLearnMoreOptionalTextTextNode: learnNode} = setItem
....
</>
and i have the next error: Parsing error: Unexpected token ... = setItem, i thought what it is
EsLinterror and used // eslint-disable-next-line to disable it, but it didn't work.
UPD full return code:
return (
<div className={generalServiceItemClassName} key={guuid()}>
{setItems.map(setItem => (
const { childContentfulPartFeatureSetLearnMoreOptionalTextTextNode: learnNode} = setItem
<div
key={guuid()}
className={cx(columnSizeClass, "service-items__item")}
data-test="service-items"
>
{setItem.learnMore ? (
<LearnMore
className="service-items__item-learn-more-container"
learnMoreLink={setItem.learnMore}
text={}
textClassName="service-items__item-texts-learn-more"
learnMoreText={learnNode ? learnNode.setItem : null}
>
{renderItem(setItem)}
</LearnMore>
) : (
renderItem(setItem)
)}
</div>
))}
</div>
)
You can't have a const declaration within an expression, and when you use the concise form of an arrow function (=> without a { after it), the body is an expression.
You can destructure in the parameter list, though. For instance:
{setItems.map(({childContentfulPartFeatureSetLearnMoreOptionalTextTextNode: learnNode}) => (
// ...use `learnNode` here...
In context:
return (
<div className={generalServiceItemClassName} key={guuid()}>
{setItems.map(({childContentfulPartFeatureSetLearnMoreOptionalTextTextNode: learnNode}) => (
<div
key={guuid()}
className={cx(columnSizeClass, "service-items__item")}
data-test="service-items"
>
{setItem.learnMore ? (
<LearnMore
className="service-items__item-learn-more-container"
learnMoreLink={setItem.learnMore}
text={}
textClassName="service-items__item-texts-learn-more"
learnMoreText={learnNode ? learnNode.setItem : null}
>
{renderItem(setItem)}
</LearnMore>
) : (
renderItem(setItem)
)
}
</div>
))}
</div>
);
Try something like this. (destructure and renaming)
const setItems = [{ abc: 5 }];
return (
<>
{setItems.map((setItem) => {
const { abc: xyz } = setItem;
return <div>{xyz}</div>;
})}
</>
);
// Alternate way, simplified.
return (
<>
{setItems.map(({ abc: xyz }) => (
<div>{xyz}</div>
))}
</>
);

Categories