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
Related
I'm trying to render some questions to evaluate the old device price. From backend I'm receiving multiple questions and I have to give a radio button to the question for YES/NO to for the selection, But when I click One radio button other buttons also get clicked. How to fix this.
My code.
const [radioValue, setRadioValue] = useState('0')
const radios = [
{ name: 'Yes', value: '1' },
{ name: 'No', value: '0' }
And this is the rendering part:
{specialQuestLoading ? (
<Loader></Loader>
) : specialQuestError ? (
<Message color="danger"> {specialQuestError} </Message>
) : (
<>
{specialQuestions ? (
specialQuestions.map((question) => (
<Card classNames="mx-2 py-2" key={question.id}>
{question.question_brand === order.prod_brand ? (
<>
<Card.Title> {question.question}</Card.Title>
<Row>
{' '}
<Col md={4}> </Col>
<ButtonGroup className="mb-2">
{radios.map((radio, idx) => (
<ToggleButton
key={idx}
id={`radio-${idx}`}
type="radio"
variant="secondary"
name="radio"
value={radio.value}
checked={radioValue === radio.value}
onChange={(e) => setRadioValue(e.currentTarget.value)}
>
{radio.name}
</ToggleButton>
))}
</ButtonGroup>
<>
<br />
</>
</Row>
</>
) : (
<></>
)}
</Card>
))
) : (
<></>
)}
</>
)}
And this is the problem. Both get checked clicking the one.
Any body knows how to fix this, Or How can I fix this ?
You are using single state for every specialQuestions Card. So changing any of the ToggleButton affects every Card Element (specialQuestions).
You should split the Card Element to a separate Component and manage the radioValue state there.
export const Card = ({question}) => {
const [radioValue, setRadioValue] = useState('0')
const radios = [
{ name: 'Yes', value: '1' },
{ name: 'No', value: '0' }
return (
<Card classNames = "mx-2 py-2" key = {question.id} >
{question.question_brand === order.prod_brand ? (
<>
<Card.Title >
{question.question}
</Card.Title>
<Row>
{' '}
<Col md = {4}>< /Col>
<ButtonGroup className = "mb-2" >
{radios.map((radio, idx) => (
<ToggleButton
key = {idx}
id = {`radio-${idx}`}
type = "radio"
variant = "secondary"
name = "radio"
value = {radio.value}
checked = {radioValue === radio.value}
onChange = {
(e) => setRadioValue(e.currentTarget.value)
}
>
{radio.name}
</ToggleButton>
))
}
</ButtonGroup>
<><br /></>
</Row>
</>)
: ( <></>)
}
</Card>
)
}
And consume it as
specialQuestions.map((question) => (
<Card question={question} />
)
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.
This is my scenario
<List>
{mainTags.map((mainTagItem) => {
return (
<ListItem onClick={() => { setMainTag(mainTagItem.tag.tagId) }} button className={classes.mainTagItem}>
<div className={classes.mainTagCircle}></div>
<ListItemText
primary={mainTagItem.tag.name}
/>
</ListItem>
)
})}
</List>
when i click on my ListItem ( that becomes selected ) i want the element <div className={classes.mainTagCircle}> has an active class
For Example:
<div classes={{ root: !!listItemSelected ? classes.mainTagCircleActive : classes.mainTagCircle, }}></div>
I have already a method onClick in my ListItem, how can i apply this logic?
given that you have a mainTag state you could compare with your element tagId to define which class to select. If it's the same as your state then active class wil be returned:
<div className={
mainTag === mainTagItem.tag.tagId
? classes.mainTagCircleActive
: classes.mainTagCircle}>
</div>
Solution with a library
You could try with this library clsx. Then do something like this:
function Component() {
const [mainTag, setMainTag] = useState(null);
return (
<List>
{mainTags.map((mainTagItem) => {
return (
<ListItem onClick={() => { setMainTag(mainTagItem.tag.tagId) }} className=
{clsx([classes.mainTagItem, mainTag === mainTagItem.tag.tagId ? :
'activeClass': 'defaultClass' ])}>
<div className={classes.mainTagCircle}></div>
<ListItemText
primary={mainTagItem.tag.name}
/>
</ListItem>
)
})}
</List>
)
}
Solution without libraries
function Component() {
const [mainTag, setMainTag] = useState(null);
return (
<List>
{mainTags.map((mainTagItem) => {
return (
<ListItem onClick={() => { setMainTag(mainTagItem.tag.tagId) }} className={
mainTag === mainTagItem.tag.tagId
? classes.mainTagCircleActive
: classes.mainTagCircle}
/>
</ListItem>
)
})}
</List>
)
}
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 ...
};
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