Reputation: 117
import "./styles.css";
import React, { useState } from "react";
import { IconButton } from "@material-ui/core";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
export default function App() {
const [expand, setExpand] = useState({
arrowA: false,
arrowB: false,
arrowC: false,
arrowD: false
});
const handleChange = (e) => {
setExpand({
...expand,
[e.currentTarget.name]: !expand.arrowA,
[e.currentTarget.name]: !expand.arrowB,
[e.currentTarget.name]: !expand.arrowC,
[e.currentTarget.name]: !expand.arrowD
});
};
return (
<div className="App">
<h1>React conditional rendering</h1>
<h2>
The component below should render if the user clicks on the arrow, and
be removed if the user clicks the arrow again.
</h2>
<h5>
This arrow should show the first part of the text.{" "}
<IconButton
variant="contained"
size="small"
color="primary"
aria-label="expand"
name="arrowA"
onClick={handleChange}
>
{<ExpandMoreIcon />}
</IconButton>
</h5>
<h5>
This arrow show the second part of the text if clicked, and be possible
to remove.
<IconButton
variant="contained"
size="small"
color="primary"
aria-label="expand"
name="arrowB"
onClick={handleChange}
>
{<ExpandMoreIcon />}
</IconButton>
</h5>
<h5>
This arrow should show the third part of the text below.{" "}
<IconButton
variant="contained"
size="small"
color="primary"
aria-label="expand"
name="arrowC"
onClick={handleChange}
>
{<ExpandMoreIcon />}
</IconButton>
</h5>
<h5>
This was really the last part.{" "}
<IconButton
variant="contained"
size="small"
color="primary"
aria-label="expand"
name="arrowD"
onClick={handleChange}
>
{<ExpandMoreIcon />}
</IconButton>
</h5>
{expand.arrowA ? (
<h2>
This is the first start of the story, let's see if we can add the
rest.
</h2>
) : null}
{expand.arrowB ? (
<h2>This is the middle part, it starts to break soon.</h2>
) : null}
{expand.arrowC ? (
<h2>
We are nearing the end. But as you see, this state management is not
optimal.
</h2>
) : null}
{expand.arrowD ? (
<h2>
This is was all I wanted to show. But why is removing this so hard?
How to make this better?
</h2>
) : null}
</div>
);
}
first of all, thanks for being here! I am a beginner in React and have a question regarding how to make my state management more optimal and better working.
I am trying to render multiple components in one React hook, to avoid having to create many different hooks. But my solution isn't working properly and not very optimal. I lack knowledge how to make the state more dynamic, but I feel I am close. Here is the example in: Code Sandbox
If you open the Code Sandbox, in the second attempt file, I am trying to set [e.currentTarget.value]: [e.currentTarget.status]
to try to get the status from the IconButton, which I there store as status={!expand.checkedA}
. But that isn't how React state management works apparently 😅.
Could someone enlighten me on what's best practice here? If you have a recommendation for an alternative way to conditionally render multiple components, I'd also be curious.
Cheers.
Upvotes: 0
Views: 634
Reputation: 3505
I think you're doing fine I would just change a few things to make it work:
First make the handleChange do this instead of the current code:
const handleChange = (e) => {
setExpand({
...expand,
[e.currentTarget.name]: !expand[e.currentTarget.name]
});
};
In this way you will only change the one you're clicking and the rest will stay the same.
Secondly you don't need the ternary operator in your jsx, you can use the && operator:
{expand.arrowA && (
<h2>
This is the first start of the story, let's see if we can add the
rest.
</h2>
)}
Check the forked sandbox if you have questions: https://codesandbox.io/s/cool-fog-h7vct?file=/src/App.js:2073-2226
Upvotes: 1