Reputation: 941
I have faced this issue multiple times and am not sure what is the best approach. Say I have 3+ components how can I have a state tracker for each of them? Do I need n
useState()
hooks for n
components?
In this example, I want to change the image displayed with onMouseOver()
. The way I did it, the hook state is applied to all the images, which is not what I desire to do.
I want to have eventually a custom drop-down menu with onClick()
particular to the image folder. So in that sense, I need an individual state tracker for each component?
const openFolder = "https://i.postimg.cc/V6L7kBCV/folder-Open.png";
const closedFolder = "https://i.postimg.cc/hG0yn3fm/folder-Closed.png"
function App() {
const [image, setImage] = React.useState(closedFolder);
const handleMouseOver = () => {
setImage(openFolder);
}
const handleMouseLeave = () => {
setImage(closedFolder);
}
return (
<div className="window">
<div className="slider">
<div className="container">
{buildLatexFolder(image,handleMouseOver,handleMouseLeave)}
</div>
</div>
</div>
);
}
const buildLatexFolder = (image,handleMouseOver,handleMouseLeave) => {
const courseNames = [
'A', 'B', 'C', 'D', 'E', 'F'
//and many more other
]
var folders = courseNames.map((value, index) => {
return (
<div className="folderContainer">
<span>{value}</span>
<div onMouseEnter={() => {handleMouseOver()}} onMouseLeave={() => {handleMouseLeave()}}>
<img src={image} width="130"/>
</div>
</div>
);
});
return folders;
}
ReactDOM.render(<App />, document.querySelector("#app"));
.window {
width: 500px;
height: 130px;
display: flex;
align-items: center;
margin-left: auto;
margin-right: auto;
}
.slider {
border-radius: 0px 0px 16px 16px;
background-color: #1F1F1F;
color: #ffffff;
overflow: hidden;
float: right;
}
.container {
display: flex;
width: 700px;
height: 130px;
margin-top: 10px;
align-items: center;
text-align: center;
}
.folderElement {
margin-left: 12px;
margin-right: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
with JSFiddle here
Previously, when faced with this problem I would just make, say, 3 hooks for my 3 components and handle the logic this way. But now I have a large number of components and don't know what is the best approach.
I have searched online 'React Should I have a hook for each component', 'How many hooks to have for components', and so on and so forth but the search results are inaccurate with what I am trying to find, or for that matter my question is inaccurate. I don't know how to proceed.
Does anyone know how I can fix this issue?
Upvotes: 0
Views: 92
Reputation: 2737
You need to have component modularization in your application. Then you can have a single CourseFolder
which can be used as a child component resides in your parent component which is App
. Using map
, you can view multiple child components having different courseDetails
inside them.
Refer the following code-snippets I created to solve your issue.
App.js
import React from "react";
import CourseFolder from "./CourseFolder";
// import "./folderStyles.css"; /* kept the styles posted in the question */
const courseNames = [
"A",
"B",
"C",
"D",
"E",
"F",
//and many more other
];
function App() {
return (
<div className="window">
<div className="slider">
<div className="container">
{courseNames.map((value, index) => (
<CourseFolder value={value} key={index} />
))}
</div>
</div>
</div>
);
}
export default App;
Then create the child component as follows.
CourseFolder.js
import React from "react";
const openFolder = "https://i.postimg.cc/V6L7kBCV/folder-Open.png";
const closedFolder = "https://i.postimg.cc/hG0yn3fm/folder-Closed.png";
function CourseFolder(props) {
const { value, key } = props;
const [image, setImage] = React.useState(closedFolder);
const handleMouseOver = () => {
setImage(openFolder);
};
const handleMouseLeave = () => {
setImage(closedFolder);
};
return (
<div className="folderContainer" key={key}>
<span>{value}</span>
<div
onMouseEnter={() => {
handleMouseOver();
}}
onMouseLeave={() => {
handleMouseLeave();
}}
>
<img src={image} width="130" alt="alternative" />
</div>
</div>
);
}
export default CourseFolder;
Hope this would be helpful to solve your issue.
Upvotes: 1