Add condition to arrow function - javascript

I have the below code snippet,
{categoriesWithSub.length > 0 &&
categoriesWithSub.map(item => {
//Add new condition here
const pageChanges = {
catId: item.id,
catName: item.catName,
};
return (
<Tile
to="./request"
text={item.catName}
key={item.id}
onClick={() => handleChange('departments', pageChanges)}
/>
);
})}
how can I add to the below a sub condition on item, something like that:
item.subCategories.length > 0 ?
return (...):
retrun (
<Tag
text={''}
to="../exact-request"
key={0}
onClick={() => handleChange('request', '')}
/>
I tried that but something is wrong with the syntax:
{categoriesWithSub.length > 0 &&
categoriesWithSub.map(item => {
item.subCategories.length > 0 ?(
const pageChanges = {
catId: item.id,
catName: item.catName,
};
return (
<Tile
to="./request"
text={item.catName}
key={item.id}
onClick={() => handleChange('departments', pageChanges)}
/>
);
):
retrun (
<Tag
text={''}
to="../exact-request"
key={0}
onClick={() => handleChange('request', '')}
/>
)
})}

return (item.subCategories.length > 0) ?
(...):
(
<Tag
text={''}
to="../exact-request"
key={0}
onClick={() => handleChange('request', '')}
/>
)

Iam not sure I got it completly what you wanted, but you can just add the condition there. But I would say doing this in render is bad practice, in render you should render this should be a function or component.
{
categoriesWithSub.length > 0 &&
categoriesWithSub.map(item => {
if (item.subCategories.length > 0 ) {
return something
}
return somethingElse
})
}
or if you insist on using ternars
{
categoriesWithSub.length > 0 &&
categoriesWithSub.map(item => {
return item.subCategories.length > 0 ?
something :
somethingElse
})
}

It's litle strange aproach but it's simple:
return item.subCategories.length > 0 ?
(
<Some ... />
) :
(
<Tag
text={''}
to=../exact-request
key={0}
onClick={() => handleChange('request', '')}
/>
);
But i recomend you writing code like this:
if (item.subCategories.length > 0) {
return <Some ... />
}
return (
<Tag
text={''}
to=../exact-request
key={0}
onClick={() => handleChange('request', '')}
/>)
Your code must be readable

You can return that condition in the beginning if falsey:
{categoriesWithSub.length > 0 &&
categoriesWithSub.map(item => {
const someCondition = <...>
if (!someCondition) return false;
// rest of your code

Related

How to handle arrays in a Grommet DataTable?

I'm trying to use arrays in Grommet DataTable. My data looks like this :
{
customer: [
'BANANA',
'Banana',
'banana',
'republic of banana'
],
somethingelse: ['ABC','123','DEF']
}
In a regular Grommet Table , I'm able to use every cell by defining the first value from the array as title - for example customer[0] - and create an expandable arrow to show the rest of the data in 'customer' :
But I don't get how to do this on a cell basis for a Grommet DataTable ?
Here is the way I'm using it in the regular Grommet Table :
<TableCell scope="row" pad={{ left: '2px', righ: '3px' }}>
<TextInput name="tags" size="xsmall" />
</TableCell>
</TableRow>
{searchResults.length > 0 &&
searchResults.map((searchResult, index) => (
<TableRow key={index}>
<TableCell>
<Box direction="row">
<Text size="xsmall">{searchResult.customer[0]}</Text>
{searchResult.customer.length > 1 && (
<Button
plain
hoverIndicator={false}
icon={
isExpanded[index] ? (
<FormDown size="18px" />
) : (
<FormNext size="18px" />
)
}
onClick={() => toggleOpen(index)}
/>
)}
</Box>
<Box>
{isExpanded[index] && listElements(searchResult.customer)}
</Box>
</TableCell>
Here is my Form , using DataTable :
return (
<Form value={formData} onSubmit={onSubmit} onChange={onChange}>
...
<DataTable
fill
border={{ body: 'bottom' }}
paginate
columns={columns}
data={searchResults}
select={select}
onClickRow={(e) => console.log(e.datum)}
onSelect={() => {}}
step={8}
rowDetails={(row) => { // I'm able to use rowDetails to expand and display some data , but how can I use this to 1. Use the [0] element of the array as title and 2. apply to all cells in the row/table.
for (const cell in row) {
// if (cell.length > 1) {
// return listElements(cell);
// }
console.log(cell);
}
}}
...
/>
...
</Form>
);
I was able to achieve that by using the render function and passing a CellElement to it, in which I have created my rules :
const columns = [
{
property: 'customer',
header: <FormField label="Customer" name="customer" size="xsmall" />,
render: (datum) => <CellElement val={datum.customer} />,
},
CellElement.js
import { Box, Text, Button } from 'grommet';
import { FormNext, FormDown } from 'grommet-icons';
import React, { useState } from 'react';
const CellElement = ({ val }) => {
const title = Array.isArray(val) ? val[0] : val;
const [isExpanded, setIsExpanded] = useState({});
const toggleOpen = (category) => {
setIsExpanded({
...isExpanded,
[category]: !isExpanded[category],
});
};
const listElements = (arr) => {
return arr.slice(1).map((el, index) => (
<Text key={index} size="xsmall">
{el}
</Text>
));
};
return (
<Box>
<Box direction="row">
<Text size="xsmall">{title}</Text>
{Array.isArray(val) && val.length > 1 && (
<Button
plain
hoverIndicator={false}
icon={
isExpanded[title] ? (
<FormDown size="18px" />
) : (
<FormNext size="18px" />
)
}
onClick={() => toggleOpen(title)}
/>
)}
</Box>
<Box>{isExpanded[title] && listElements(val)}</Box>
</Box>
);
};
export default CellElement;

Whole page reloading after changing one state

I'm currently building a page with a ton of Charts, and I'm using a Material UI menu to kinda switch around graphs.
When I click on a new MenuItem it changes my part state and displays a new array of components.
My main problem right now is that whenever I click on the button, all the charts do a quick load, but with this amount of charts this is a problem.
I've tried debugging it, but to be honest I couldn't find a problem, all my states are set when they need to be set, and useEffects are running just once on the beginning, so no extra loads.
This is what it looks like:
And this would be the code that I'm currently rendering. If you need any further info from my code just let me know and if you can provide any advice for the improvement of my code I would be glad, thanks.
<>
<div className={classes.actionBar}>
<SelectEstimatedMonthForm />
</div>
<div>
<Card>
<div>
<h1>Gráficos de DRE</h1>
<Button
aria-controls="simple-menu"
aria-haspopup="true"
onClick={handleClick}
>
Open Menu
</Button>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>Todos Gráficos</MenuItem>
<MenuItem onClick={handleClose}>
Gráficos DRE Orçamento Evolução
</MenuItem>
<MenuItem onClick={handleClose}>
Gráficos de Evolução Parte 2
</MenuItem>
<MenuItem onClick={handleClose}>
Gráficos de Representatividade
</MenuItem>
</Menu>
</div>
<div>
{chartDataPart?.part1 && part === 1 && values && (
<div>
{chartDataPart?.part1?.map((data) => {
if (data?.type === "bar") {
return (
<div>
{data?.labels && (
<ChartBar
data={data}
text={data?.text}
noLabel={data?.noLabel}
stacked={data?.stacked}
newPlugin={data?.customPlugin}
/>
)}
</div>
);
} else if (data?.type === "pie") {
return (
<div>
{data?.labels && (
<ChartPie text={data?.text} data={data} />
)}
</div>
);
} else if (data?.type === "doughnut") {
return (
<div>
{data?.labels && (
<ChartDoughnut text={data?.text} data={data} />
)}
</div>
);
} else {
return (
<div>
<h1>{data?.text} esta sem type</h1>
</div>
);
}
})}
</div>
)}
{chartDataPart?.part2 && part === 2 && values && (
<div>
{chartDataPart?.part2?.map((data) => {
if (data?.type === "bar") {
return (
<div>
{data?.labels && (
<ChartBar
data={data}
text={data?.text}
noLabel={data?.noLabel}
stacked={data?.stacked}
newPlugin={data?.customPlugin}
/>
)}
</div>
);
} else if (data?.type === "pie") {
return (
<div>
{data?.labels && (
<ChartPie text={data?.text} data={data} />
)}
</div>
);
} else if (data?.type === "doughnut") {
return (
<div>
{data?.labels && (
<ChartDoughnut text={data?.text} data={data} />
)}
</div>
);
} else {
return (
<div>
<h1>{data?.text} esta sem type</h1>
</div>
);
}
})}
</div>
)}
{chartDataPart?.part3 && part === 3 && values && (
<div>
{chartDataPart?.part3?.map((data) => {
if (data?.type === "bar") {
return (
<div>
{data?.labels && (
<ChartBar
data={data}
text={data?.text}
noLabel={data?.noLabel}
stacked={data?.stacked}
newPlugin={data?.customPlugin}
/>
)}
</div>
);
} else if (data?.type === "pie") {
return (
<div>
{data?.labels && (
<ChartPie text={data?.text} data={data} />
)}
</div>
);
} else if (data?.type === "doughnut") {
return (
<div>
{data?.labels && (
<ChartDoughnut text={data?.text} data={data} />
)}
</div>
);
} else {
return (
<div>
<h1>{data?.text} esta sem type</h1>
</div>
);
}
})}
</div>
)}
{chartData && part === 0 && values && (
<div>
{chartData?.map((data) => {
if (data?.type === "bar") {
return (
<div>
{data?.labels && (
<ChartBar
data={data}
text={data?.text}
noLabel={data?.noLabel}
stacked={data?.stacked}
newPlugin={data?.customPlugin}
/>
)}
</div>
);
} else if (data?.type === "pie") {
return (
<div>
{data?.labels && (
<ChartPie text={data?.text} data={data} />
)}
</div>
);
} else if (data?.type === "doughnut") {
return (
<div>
{data?.labels && (
<ChartDoughnut text={data?.text} data={data} />
)}
</div>
);
} else {
return (
<div>
<h1>{data?.text} esta sem type</h1>
</div>
);
}
})}
</div>
)}
</div>
</Card>
</div>
</>
useEffect(() => {
const fetchDreData = async () => {
try {
const res = await http.get(
`call1`
);
const data = await res.data;
const final = data.data;
// console.log(final);
setEstimatedMonths(final);
} catch (e) {
console.log("error", e);
}
};
const fetchProductsData = async () => {
try {
const res = await http.get(
`call2`
);
const data = await res.data;
const final = data.data;
// console.log(res);
setEstimatedProducts(final);
} catch (e) {
console.log("error", e);
}
};
fetchDreData();
fetchProductsData();
// console.log("useffect1");
}, [estimatedMonthContext.monthId]);
useEffect(() => {
if (estimatedProducts && estimatedMonths) {
// console.log("useffect2");
flatData();
}
// productsFlatData();
}, [estimatedProducts, estimatedMonths]);
useLayoutEffect(() => {
// if (values) {
chart();
// console.log("useffect3");
// }
}, [values]);
Something on your page is causing the page to rerender again after load, which would be either a state change or most likely the useEffect.
If you are using useEffect make sure you're doing it correctly by 1. not updating state inside it or 2. returning '[]'.
useEffect(() => {
}, []) // this part here
Along with that you're fetching data from multiple endpoints and each time updating the state every time the data returns, which will cause the page to rerender multiple times. Instead you should move each component to their own respective individual components and fetch their own data individually so they don't affect each other and update the whole page.

React spring auto height not working properly

React spring auto height not working properly.
I am trying to create animation for auto height with react spring, I already achieved the animation but if I go to another page and go back to the page that I have auto height animation it's not working until I refresh the page. How can I fix this problem?
Here is my code:
const defaultHeight = "100px";
const [contentHeight, setContentHeight] = useState(defaultHeight);
const [ref, { height }] = useMeasure();
const expand = useSpring({
config: { ...config.default, duration: 250 },
height: `${contentHeight}px` || defaultHeight,
});
useEffect(() => {
setContentHeight(height);
window.addEventListener("resize", setContentHeight(height));
return window.removeEventListener("resize", setContentHeight(height));
}, [height]);
return (
<div className="team-management">
<div className="team-management-tabs-header">
<div className="team-management-tab-items">
{tabs.map((tab, index) => (
<div
id={editable === true ? "" : `${tab}`}
className={
activeTab === index
? "team-management-tab-item selected"
: "team-management-tab-item"
}
key={tab}
role="button"
tabIndex={tab}
onKeyPress={() => {
return;
}}
onClick={() => {
if (editable === true) {
setActiveTab(index);
} else if (index !== 5 && index !== 6) {
setActiveTab(index);
}
}}
>
{teamData.type === "organization" ? (
<span className="tab-item-text">{tab}</span>
) : (
<>
{tab !== "Sub-Team" && (
<span className="tab-item-text">{tab}</span>
)}
</>
)}
<span className="tab-item-indicator" />
</div>
))}
</div>
</div>
<animated.div style={expand}>
<div className="team-management-tab-panes" ref={ref}>
{tabs[activeTab] === "Mission" && (
<Mission
editable={editable}
teamId={teamId}
teamData={teamData}
fetchTeamData={fetchTeamData}
notify={notify}
/>
)}
{tabs[activeTab] === "Managers" && <Managers members={members} />}
{tabs[activeTab] === "Members" && (
<Members
members={members}
teamId={teamId}
tab={tabs[activeTab]}
userPublicId={userPublicId}
fetchTeamData={fetchTeamData}
notify={notify}
/>
)}
{tabs[activeTab] === "Invitees" && (
<Invitees
teamData={teamData}
teamId={teamId}
privateTeamId={teamData.id}
fetchTeamData={fetchTeamData}
tab={tabs[activeTab]}
/>
)}
{tabs[activeTab] === "Sub-Team" && (
<SubTeam
teamId={teamId}
teamData={teamData}
members={members}
fetchTeamData={fetchTeamData}
/>
)}
</div>
</animated.div>
</div>
);
Thank you for helping me out

Double conditional rendering in react?

I'm building a small clothing store app in React, just to learn things. I implemented a filter by price section but I would want to be able to write a condition for the case in which there's no item in the selected price range, instead of the page being blank.
render() {
const filteredOpt2 = this.state.items.filter(item => item.price <= 60);
const filteredOpt3 = this.state.items.filter(item => item.price >= 60 && item.price <= 100);
return (
<div>
{
this.state.selectedOption === "option1"
? <ProductList products={this.state.items} style={{marginLeft: 0}}/>
: this.state.selectedOption === "option2"
? <ProductList products={filteredOpt2} style={{marginLeft: 0}}/>
: this.state.selectedOption === "option3"
? <ProductList products={filteredOpt3} style={{marginLeft: 0}}/>
: null
}
</div>
)
}
I know the code is very repetitive and really not ideal, but I couldn't come up with a better approach for now.
So what I wish to do, is, let's say the filteredOpt2 results in an empty array, how and where could I implement a condition that says if this happens, display a p tag showing a text?
If not diving deep in the idea of component split you can just add condition in the template like this
const filteredOpt2 = this.state.items.filter((item) => item.price <= 60);
const filteredOpt3 = this.state.items.filter(
(item) => item.price >= 60 && item.price <= 100
);
return (
<div>
{this.state.selectedOption === "option1" ? (
<ProductList products={this.state.items} style={{ marginLeft: 0 }} />
) : this.state.selectedOption === "option2" ? (
<>
{filteredOpt2.length > 0 ? (
<ProductList products={filteredOpt2} style={{ marginLeft: 0 }} />
) : (
<p>No items lower than 60</p>
)}
</>
) : this.state.selectedOption === "option3" ? (
<>
{filteredOpt3.length > 0 ? (
<ProductList products={filteredOpt3} style={{ marginLeft: 0 }} />
) : (
<p>No items between 60 and 100</p>
)}
</>
) : null}
</div>
You are sending the product list down to ProductList component via props. In that component, where you use your props.products, you can add something like this:
{!props.products.length
? <p>No product matched the criteria</p>
: props.products.map(product => {... whatever your code is })
}
To elaborate, if the products.length is zero, you show your 'no product' text, otherwise, show the products.
You can do the filtering in advance, e.g. in a function and then render the list accordingly:
const filterItems = (items, filter) => {
if (filter === "option1") return items;
if (filter === "option2") return items.filter(item => item.price <= 60);
if (filter === "option3") return items.filter(item => item.price >= 60 && item.price <= 100);
};
render() {
const filtered = filterItems(this.state.items, this.state.selectedOption);
return (
<div>
{filtered.length === 0 ? (
<p>No products</p>
) : (
<ProductList products={filtered} style={{marginLeft: 0}}/>
)}
</div>
);
}
or even better let the ProductList component handle that:
render() {
return (
<div>
<ProductList
products={filterItems(this.state.items, this.state.selectedOption)}
style={{marginLeft: 0}}
/>
</div>
);
}
const ProductList = ({products}) => {
if (products.length === 0) return <p>No products</p>;
return ...
};

material ui SingleExpand TreeView property?

I want to prevent that when I click on several items, I have several items (expand: "true")
I would like that when I click on a new item, the old one goes back to its original state (expand: "false")
However, I did not find any property in the documentation to handle this.
https://material-ui.com/components/tree-view/
{stoMenu && (
<TreeView
style={layout.menu}
defaultCollapseIcon={<KeyboardArrowUpIcon />}
defaultExpandIcon={<KeyboardArrowDownIcon />}
>
{stoMenu.root.children.map(menu => {
return (
<TreeItem
key={menu.nodeId}
nodeId={menu.nodeId}
label={
<ListItem
style={layout.menuListItem}
className={menu.iconCls}
>
<ListItemText
style={layout.menuText}
primary={menu.text}
onClick={() => {
if (menu.id === '/accueil') {
this.props.history.push(menu.id);
}
}}
/>
</ListItem>
}
>
{menu.children.map(child => {
return (
<TreeItem
// style={layout.subMenuText}
className={classes.subMenu}
key={child.nodeId}
nodeId={child.nodeId}
label={child.text}
onClick={() => {
if (child.id) {
this.props.history.push(child.id);
}
}}
/>
);
})}
</TreeItem>
);
})}
</TreeView>
)}

Categories