I am trying to push the {database, id} to the end of the databaseChanges object which will be stored in a state variable as I want to access all of them. However I am getting undefined when I try to set it a new state variable (setDatabaseArr).
Here is my code:
const UnitTestsDatabaseView = props => {
const [databaseArr, setDatabaseArr] = useState('')
const addToProduction = test => () => {
const databaseChanges = props.unitTestsData.map(test => {
return {
"unit_test_id": test.id,
"databases": test.databases
}
})
const { databases, id } = test
console.log(databases, id)
databaseChanges.push(databases, id)
setDatabaseArr(databases, id)
console.log( setDatabaseArr(databases, id))
console.log( databaseChanges.push(databases, id))
}
return (
<div>
<div className='Card' style={{marginTop: '40px', overflow: 'hidden'}}>
<div className='TableTopbar UnitTestsGrid'>
<div>ID</div>
<div>Name</div>
<div>Database</div>
<div />
</div>
{props.unitTestsData && props.unitTestsData.map(test =>
<div key={test.id} className='Table UnitTestsGrid' style={{overflow: 'hidden'}}>
<div>{test.id}</div>
<div>{test.unit_test_name}</div>
<div>{test.databases}
<div>
<Checkbox
mainColor
changeHandler={addToProduction(test)}
data={{}}
id={test.id}
/>
</div>
</div>
</div>
)}
</div>
</div>
)
}
export default withRouter(UnitTestsDatabaseView)
I review your code, It seems there is a problem with the implementation on how to push a value to the state.
I tried to reproduce the problem and try to implement of which I think a solution.
And here is the code
import React, { useState, useEffect } from "react";
import { Checkbox } from "#material-ui/core";
// In order to reproduce the propblem
// Lets that these are the values of the unitTestsData props
// and instead of passing this as value of a props
// I defined it right here.
const unitTestsData = [
{ id: 1, unit_test_name: "Unit I", databases: "test1" },
{ id: 2, unit_test_name: "Unit II", databases: "test2" },
{ id: 3, unit_test_name: "Unit III", databases: "test3" }
];
const UnitTestsDatabaseView = () => {
const [databaseArr, setDatabaseArr] = useState([]);
// Maybe you want to push data if the checkbox is checked
// and pop the data if checkbox is unchecked :: Yes ???
// This is how you do it.
const addToProduction = ({ target }, { id, databases }) => {
setDatabaseArr((previousState) => {
let newState = [...previousState];
if (target.checked) {
newState = [
...newState,
{ unit_test_id: newState.length + 1, databases }
];
} else {
const i = newState.findIndex(({ unit_test_id }) => unit_test_id === id);
if (i !== -1) newState.splice(i, 1);
}
return newState;
});
};
useEffect(() => {
console.log("databaseArr", databaseArr);
}, [databaseArr]);
return (
<div>
<div className="Card" style={{ marginTop: "40px", overflow: "hidden" }}>
<div className="TableTopbar UnitTestsGrid">
<div>ID</div>
<div>Name</div>
<div>Database</div>
</div>
{unitTestsData.map((test) => {
const { id, unit_test_name, databases } = test;
return (
<div
key={id}
className="Table UnitTestsGrid"
style={{ overflow: "hidden" }}
>
<div>{id}</div>
<div>{unit_test_name}</div>
<div>
{databases}
<div>
<Checkbox
color="secondary"
onChange={(e) => addToProduction(e, test)}
data={{}}
id={id.toString()}
/>
</div>
</div>
</div>
);
})}
</div>
</div>
);
};
export default UnitTestsDatabaseView;
You may click the codesandbox link to see the demo
https://codesandbox.io/s/pushing-value-49f31
Related
It's saying state.map is not a function but it works just fine before i call the handleclick function.I am stuck here and would like to know why its giving me the state.map is not a function error. Added bonus too would
be me asking how does one setState when you have objects inside objects.
For example if id like to return with setStatea {...item, value:false} value is inside and object thats inside and object. How would I specifically target the value I need inside and array of objects. Thank you.
import React from "react";
import Quiz from "./components/Quiz";
import Menu from "./components/Menu";
import { v4 as uuidv4 } from 'uuid'
function App() {
const [state,setState] = React.useState([])
const [start,setStart] = React.useState(false)
React.useEffect(()=> {
if(start === true){
console.log(state)
fetch("https://opentdb.com/api.php?amount=5&category=27&difficulty=easy&type=multiple")
.then(res => res.json())
.then(data => setState(data.results.map(item =>
({selectedQuestion: "",
buttons: item.incorrect_answers.concat(item.correct_answer).map(item =>
({use: item ,value: false, id: uuidv4()})),
questions: item.question
}))))
}} , [start])
function startGame () {
setStart(prevState => !prevState)
}
const myButtons = state.map(function(item) {
return (<Quiz
key={uuidv4()}
buttons={item.buttons}
value ={item.buttons.map(item => item.value)}
question = {item.questions}
handleClick ={(event) =>handleClick(event.target.value)}
/> ) })
console.log(state.map(item => item))
function handleClick (event) {
if (event === "false"){
//this is what is giving me issues//
setState(item => (
{
...item, selectedQuestion: "howdy"
}))
//////////////////////////////////////////////////////////////
}
else {
console.log("hi")
}
}
return (<div>
{start === false ? <Menu
startGame ={startGame}
/> : <div className="parent--quiz">
<div className="quiz">
{myButtons}
</div>
</div>
}
</div>
)
}
export default App;
Quiz component is here
function Quiz (props) {
const styles ={
backgroundColor: props.value === true ? "red" : "#D6DBF5"
}
return (
<div>
<div className="cards" style={{ borderTop: "2px solid #fff ", marginLeft: 20, marginRight: 20 }}>
<h1 className="quiz--h1">{props.question}</h1>
<div className="quiz--buttons-div" >
{props.buttons.map((item) => (
<button className="quiz--buttons" style={styles} value={item.value} onClick={props.handleClick}>{item.use}</button>
))}
</div>
</div>
</div>
)
}
export default Quiz
code sections are fine
I have such a project. Here I want the button border save in the local storage.The buttons are divided into categories. For example when you refresh the page after selecting a sports button, the border of the button disappears. I want save btn border in the localstorage. I saved the categories in memory, but I can't make the border of the selected button.How can I fix it?
import React, { useEffect, useState } from "react";
import SpinnerLoad from './components/SpinnerLoad'
import NewsItem from "./components/NewsItem";
import Category from "./components/data/Category"
const App = () => {
const [state, setState] = useState([]);
const [loading, setLoading] = useState(false)
const [selected, setSelected] = useState('');
const fetchValue = (category, index) => {
localStorage.setItem("category", category);
localStorage.setItem("selected", index);
fetch(`https://inshorts-api.herokuapp.com/news?category=${category}`)
.then(res => res.json())
.then(res => {
setState(res.data)
setLoading(true)
})
.catch((error) => console.log(error))
setLoading(false);
};
const CategoryButton = ({ category, i }) => (
// passing index --> i to the fetch Value
<button onClick={() =>{ fetchValue(category,i) ; setSelected(i)} }
style={{border : selected === i ? '1px solid red' : null}} >{category}</button>
);
useEffect(() => {
let categoryValue = localStorage.getItem("category") || "all";
fetchValue(categoryValue)
const select = localStorage.getItem("selected") || "";
setSelected(select);
}, []);
return (
<>
<div className="header-bg">
<h1 className="mb-3">News</h1>
<div className="btns ">
{Category.map((value,i) => {
return <CategoryButton category={value} i={i}/>;
})}
</div>
</div>
<div className="news">
<div className="container">
<div className="row">
{
!loading
? <SpinnerLoad />
:
state.map((data, index) => {
return (
<NewsItem
imageUrl={data.imageUrl}
author={data.author}
title={data.title}
content={data.content}
date={data.date}
key={data.id}
/>
);
})
}
</div>
</div>
</div>
</>
);
};
export default App;
According to the code looks like you want to display data specific to a category set when the user clicks on the category buttons. and after the click, the correct data is rendered and the current category button receives a change in its style highlighting it is the current state.
I don't understand why you need to store anything in a client's localstorage,
I would not recommend storing too much in localStorage as it is limited and is used by different sites a user visits, I only store authentication tokens in localstorage and I believe that is the norm.
I've tried to create the effect you want without the need to store in local storage
import React, { useState, useCallback, useEffect } from "react";
import ReactDOM from "react-dom";
import { cat } from "../categories.js";
import { news } from "../news.js";
function Example() {
const [state, setState] = useState([]);
const [loading, setLoading] = useState(false);
const [selected, setSelected] = useState(null);
useEffect(() => {
function fetchFunction() {
setLoading(true);
for (let i = 0; i < news.length; i++) {
if (news[i].id === selected) {
const current = news[i].c;
setState(current);
}
}
setLoading(false);
}
fetchFunction();
}, [selected]);
return (
<>
<ol
style={{
width: "50%",
listStyle: "none",
display: "flex",
justifyContent: "space-between"
}}
>
{cat.map((item, index) => {
return (
<li key={index}>
<button
style={{ border: selected === item.id && "none" }}
onClick={() => {
setSelected(item.id);
}}
>
{item.name}
</button>
</li>
);
})}
</ol>
<section style={{ width: "100%", height: "70%" }}>
{state.map((item, index) => {
return (
<div
key={index}
style={{
width: "30%",
height: "30%",
background: "red",
display: "flex",
alignItems: "center",
justifyContent: "center",
margin: "1% 0 2% 0"
}}
>
{item.name}
</div>
);
})}
</section>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Example />, rootElement);
You can save the selectedIndex in localStorage and retrieve it in the useEffect..
const CategoryButton = ({ category, i }) => (
// passing index --> i to the fetch Value
// setting selected as string instead of index for type checking
<button onClick={() =>{ fetchValue(category,i) ; setSelected(`${i}`)} }
style={{border : selected === `${i}` ? '1px solid red' : null}} >{category}</button>
);
const fetchValue = (category, index) => {
localStorage.setItem("category", category);
localStorage.setItem("selected", index);
// ...
}
useEffect(() => {
const select = localStorage.getItem("selected") || "";
// passing selectedIndex to the fetchValue, otherwise it becomes
//undefined..
fetchValue(categoryValue,select)
setSelected(select);
},[])
I have a few buttons and "view all" button. The individual buttons load the coresponding data of that index or will show all the data by clicking the "view all" button. Problem I am running into is when I click my "view all" button in the parent it's not updating the state in the child component. On mounting it works as normal but on event handler in the "view all" it doesn't update. Any thoughts on where I am going wrong here?
JS:
...
const Context = createContext(false);
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
"& > *": {
margin: theme.spacing(1)
}
},
orange: {
color: theme.palette.getContrastText(deepOrange[500]),
backgroundColor: deepOrange[500],
border: "4px solid black"
},
info: {
margin: "10px"
},
wrapper: {
display: "flex"
},
contentWrapper: {
display: "flex",
flexDirection: "column"
},
elWrapper: {
opacity: 0,
"&.active": {
opacity: 1
}
}
}));
const ToggleItem = ({ id, styles, discription }) => {
const { activeViewAll, handleChange } = useContext(Context);
const [toggleThisButton, setToggleThisButton] = useState();
const handleClick = () => {
setToggleThisButton((prev) => !prev);
handleChange(discription, !toggleThisButton);
};
return (
<>
<Avatar
className={toggleThisButton && !activeViewAll ? styles.orange : ""}
onClick={handleClick}
>
{id}
</Avatar>
<p>{JSON.stringify(toggleThisButton)}</p>
</>
);
};
const ToggleContainer = ({ className, selected }) => {
return (
<div className={className}>
{selected.map((item, idx) => (
<div key={idx}>Content {item}</div>
))}
</div>
);
};
export default function App() {
const data = ["first", "second", "third"];
const classes = useStyles();
const [selected, setSelected] = useState([]);
const [activeViewAll, setActiveViewAll] = useState(false);
useEffect(() => {
setActiveViewAll(true);
setSelected([...data]);
}, []);
const handleChange = (val, action) => {
let newVal = [];
if (activeViewAll) {
selected.splice(0, 3);
setActiveViewAll(false);
}
if (action) {
newVal = [...selected, val];
} else {
// If toggle off, then remove content from selected state
newVal = selected.filter((v) => v !== val);
}
console.log("action", action);
setSelected(newVal);
};
const handleViewAll = () => {
console.log("all clicked");
setActiveViewAll(true);
setSelected([...data]);
};
return (
<Context.Provider value={{ activeViewAll, handleChange }}>
<div className={classes.wrapper}>
<Avatar
className={activeViewAll ? classes.orange : null}
onClick={handleViewAll}
>
<span style={{ fontSize: "0.75rem", textAlign: "center" }}>
View All
</span>
</Avatar>
{data.map((d, id) => {
return (
<div key={id}>
<ToggleItem id={id} styles={classes} discription={d} />
</div>
);
})}
</div>
<div className={classes.contentWrapper}>
<ToggleContainer styles={classes} selected={selected} />
</div>
</Context.Provider>
);
}
Codesanbox:
https://codesandbox.io/s/72166087-forked-jvn59i?file=/src/App.js:260-3117
Issue
The issue seems to be that you are mixing up the management of the boolean activeViewAll state with the selected state.
Solution
When activeViewAll is true, pass the data array as the selected prop value to the ToggleContainer component, otherwise pass what is actually selected, the selected state.
Simplify the handlers. The handleViewAll callback only toggles the view all state to true, and the handleChange callback toggles the view all state back to false and selects/deselects the data item.
function App() {
const data = ["first", "second", "third"];
const classes = useStyles();
const [selected, setSelected] = useState([]); // none selected b/c view all true
const [activeViewAll, setActiveViewAll] = useState(true); // initially view all
const handleChange = (val, action) => {
setActiveViewAll(false); // deselect view all
setSelected(selected => {
if (action) {
return [...selected, val];
} else {
return selected.filter(v => v !== val)
}
});
};
const handleViewAll = () => {
setActiveViewAll(true); // select view all
};
return (
<Context.Provider value={{ activeViewAll, handleChange }}>
<div className={classes.wrapper}>
<Avatar
className={activeViewAll ? classes.orange : null}
onClick={handleViewAll}
>
<span style={{ fontSize: "0.75rem", textAlign: "center" }}>
View All
</span>
</Avatar>
{data.map((d, id) => {
return (
<div key={id}>
<ToggleItem id={id} styles={classes} discription={d} />
</div>
);
})}
</div>
<div className={classes.contentWrapper}>
<ToggleContainer
styles={classes}
selected={activeViewAll ? data : selected} // pass all data, or selected only
/>
</div>
</Context.Provider>
);
}
In the ToggleContainer don't use the array index as the React key since you are mutating the array. Use the element value since they are unique and changing the order/index doesn't affect the value.
const ToggleContainer = ({ className, selected }) => {
return (
<div className={className}>
{selected.map((item) => (
<div key={item}>Content {item}</div>
))}
</div>
);
};
Update
Since it is now understood that you want to not remember what was previously selected before toggling activeViewAll then when toggling true clear the selected state array. Instead of duplicating the selected state in the children components, pass the selected array in the context and computed a derived isSelected state. This maintains a single source of truth for what is selected and removes the need to "synchronize" state between components.
const ToggleItem = ({ id, styles, description }) => {
const { handleChange, selected } = useContext(Context);
const isSelected = selected.includes(description);
const handleClick = () => {
handleChange(description);
};
return (
<>
<Avatar
className={isSelected ? styles.orange : ""}
onClick={handleClick}
>
{id}
</Avatar>
<p>{JSON.stringify(isSelected)}</p>
</>
);
};
const ToggleContainer = ({ className, selected }) => {
return (
<div className={className}>
{selected.map((item) => (
<div key={item}>Content {item}</div>
))}
</div>
);
};
Update the handleChange component to take only the selected value and determine if it needs to add/remove the value.
export default function App() {
const data = ["first", "second", "third"];
const classes = useStyles();
const [selected, setSelected] = useState([]);
const [activeViewAll, setActiveViewAll] = useState(true);
const handleChange = (val) => {
setActiveViewAll(false);
setSelected((selected) => {
if (selected.includes(val)) {
return selected.filter((v) => v !== val);
} else {
return [...selected, val];
}
});
};
const handleViewAll = () => {
setActiveViewAll(true);
setSelected([]);
};
return (
<Context.Provider value={{ activeViewAll, handleChange, selected }}>
<div className={classes.wrapper}>
<Avatar
className={activeViewAll ? classes.orange : null}
onClick={handleViewAll}
>
<span style={{ fontSize: "0.75rem", textAlign: "center" }}>
View All
</span>
</Avatar>
{data.map((d, id) => {
return (
<div key={d}>
<ToggleItem id={id} styles={classes} description={d} />
</div>
);
})}
</div>
<div className={classes.contentWrapper}>
<ToggleContainer
styles={classes}
selected={activeViewAll ? data : selected}
/>
</div>
</Context.Provider>
);
}
Below is my code, I am fetching the data from api and on success I am setting the the response of state in set_ProductDetails. I want to pass the response state to different component and different page with the result and bind the data. I am using "react-router-dom": "^5.2.0".
Product_info.jsx
function GetProductDetails(products) {
const history = useHistory();
useEffect(() => {
console.log("render", history.location.state);
}, []);
return (
<>
<div>
<h1>Transaction Info</h1>
</div>
</>
);
}
export default GetProductDetails
Product_query.jsx
function ProductSearch() {
const [product_id, setProduct_id] = useState();
const [product_search, set_ProductSearch] = useState({ product_id: "" });
const [product_deatils, set_ProductDetails] = useState({ product_id: "" });
const history = useHistory();
//Handle the onSubmit
function handleSubmit() {
try {
set_ProductSearch({ address: product_id });
} catch (e) {
alert(e.message);
}
}
function onAPISuccess(data) {
history.push("/product_info/GetProductDetails", { data });
//here render blank screen
}
useEffect(() => {
const fetchData = async (product_id) => {
try {
const resp = await axios.post(
config.SERVER_URL + "/api/getProductInfo/",
product_id
);
set_ProductDetails(resp.data);
onAPISuccess(data)
} catch (err) {
console.error(err);
fetchData(product_search)
.catch(console.error);
}
}, [product_search]);
return (
<>
<div class="input-group mb-3">
<input
type="text"
class="form-control"
aria-describedby="button-addon2"
id="txt_address"
name="address"
placeholder="Address/Tx hash"
onChange={(e) => setProduct_id(e.target.value)}
></input>
<div class="input-group-append" style={{ color: "white" }}>
<button
class="btn btn-outline-success"
type="button"
id="button-addon2"
onClick={() => handleSubmit()}
>
Search
</button>
</div>
</div>
</>
);
}
export default ProductSearch
Home page
export default function Home() {
return (
<>
<main>
<div
className="col-md-12"
style={{
background: "#fff",
backgroundImage: `url(${Image})`,
height: "245px",
}}
>
<Container className="container-sm">
<Row>
<Col xs lg="5" className="justify-content-md-center">
<div>
<ProductSearch></ProductSearch>
</div>
</Col>
</Row>
</Container>
</div>
</main>
<>
)
}
Do history.push("/your_path",{..object you want to send}). Then in the component where this history.push redirects, access that object by saying history.location.state (this will return the object you passed while redirecting).
I am working where I want to automatically collapse the menu when other one opens.Now I already tried making separate useState and passing values but it doesn't work.I am sharing the before and after code with you.
In Dashboard.jsx I am maping through the menus and passing it to MenuCards.jsx as props, now if A menu is clicked hence is Expandable, it is again passed to getExpandableMenu and the menu is exapanded.
The end goal I want is one menu to open and if the other menu is clicked the first one to close first.
Before code -
// Dashboard.tsx
setMenuList([
{
title: "Thermal Comfort",
icon: thermal,
decorator: new ManekinDecorator(IModelApp.viewManager.selectedView!),
tooltip: "Thermal Comfort",
},
{
title: "Surface Plots",
icon: surfacePlot,
decorator: null,
tooltip: "Surface Plots",
},
{
title: "Contour Plots",
icon: contour,
decorator: null,
tooltip: "Contour Plots",
},
{
title: "Comfort Cloud",
icon: comfortCloud,
decorator: new ComfortDecorator(),
tooltip: "Comfort Cloud",
},
{
title: "Flowlines",
icon: flowline,
//decorator: getFlowLineDecorator(),
decorator: null,
tooltip: "FlowLines",
},
]);
} else {
setMenuList([]);
setIsDropDownVisibal(false);
}
}, [viewPort]);
<div className="menu">
<div style={{ overflowY: "scroll", width: "inherit" }}>
{menuList.map((menu) => (
<MenuCard
menu={menu.title}
icon={menu.icon}
decorator={menu.decorator}
tooltip={menu.tooltip}
/>
))}
</div>
</div>
// MenuCard.tsx
const MenuCard = (props: any) => {
const [toggle, setToggle] = React.useState(true);
const [expandOption, setExpandOption] = React.useState(false);
const onClick = () => {
if (props.decorator !== null) {
if (toggle) {
IModelApp.viewManager.decorators.forEach((decorator) => {
IModelApp.viewManager.dropDecorator(decorator);
});
IModelApp.viewManager.addDecorator(props.decorator);
} else IModelApp.viewManager.dropDecorator(props.decorator);
}
setToggle(!toggle);
setExpandOption(!expandOption);
};
const { menu, icon, tooltip } = props;
return (
<div>
<div className="mainMenu" onClick={onClick}>
<div className="icon">
<img src={icon} alt="icon" className="menuIcon" />
</div>
<div className="menuTitle">
<p className="title">{menu}</p>
</div>
<InfoTooltip tooltipText={tooltip} />
</div>
{expandOption && (
<GetExpandedMenu menuName={menu} decorator={props.decorator} />
)}
</div>
);
};
export default MenuCard;
// GetExpandedMenu.tsx
export default function GetExpandedMenu(props:any){
const {menuName} = props
const surfacePlotManager= new SurfacePlotManager()
const contourPlotManager=new ContourPlotManager();
switch(menuName) {
case 'Surface Plots':
return <SurfacePlot plotManager={surfacePlotManager}/>
case 'Thermal Comfort':
return <ThermalComfortMenu decorator={props.decorator}/>
case 'Flowlines':
return <FlowLines />
case "Contour Plots":
return <ContourPlot plotManager={contourPlotManager}/>;
case 'Comfort Cloud':
return <ComfortCloud/>
default:
return <p>expanded options</p>;
}
}
Here is what I tried doing which failed.
// MenuCard.tsx
// tried making separate useState for every menu
/* eslint-disable eqeqeq */
import React from "react";
import "./MenuCard.scss";
const MenuCard = (props: any) => {
const [toggle, setToggle] = React.useState(true);
const [expandOption, setExpandOption] = React.useState(false);
const [ThermalExpandOption, setThermalExpandOption] = React.useState(false);
const [SurfaceExpandOption, setSurfaceExpandOption] = React.useState(false);
const [ContourExpandOption, setContourExpandOption] = React.useState(false);
const [CloudExpandOption, setCloudExpandOption] = React.useState(false);
const [FlowlinesExpandOption, setFlowlinesExpandOption] = React.useState(false);
const onClick = () => {
console.log("Menu clicked is", props.id);
if (props.id == 0) {
setThermalExpandOption(!ThermalExpandOption);
setSurfaceExpandOption(false);
setContourExpandOption(false);
setCloudExpandOption(false);
setFlowlinesExpandOption(false);
} else if (props.id == 1) {
setThermalExpandOption(false);
setSurfaceExpandOption(!SurfaceExpandOption);
setContourExpandOption(false);
setCloudExpandOption(false);
setFlowlinesExpandOption(false);
} else if (props.id == 2) {
setThermalExpandOption(false);
setSurfaceExpandOption(false);
setContourExpandOption(!CloudExpandOption);
setCloudExpandOption(false);
setFlowlinesExpandOption(false);
} else if (props.id == 3) {
setThermalExpandOption(false);
setSurfaceExpandOption(false);
setContourExpandOption(false);
setCloudExpandOption(!CloudExpandOption);
setFlowlinesExpandOption(false);
} if (props.id == 4) {
setThermalExpandOption(false);
setSurfaceExpandOption(false);
setContourExpandOption(false);
setCloudExpandOption(false);
setFlowlinesExpandOption(!FlowlinesExpandOption);
}
if (props.decorator !== null) {
if (toggle) {
IModelApp.viewManager.decorators.forEach((decorator) => {
IModelApp.viewManager.dropDecorator(decorator);
});
IModelApp.viewManager.addDecorator(props.decorator);
} else IModelApp.viewManager.dropDecorator(props.decorator);
}
setToggle(!toggle);
setExpandOption(!expandOption);
};
const { menu, icon, tooltip } = props;
return (
<div>
<div className="mainMenu" onClick={onClick}>
<div className="icon">
<img src={icon} alt="icon" className="menuIcon" />
</div>
<div className="menuTitle">
<p className="title">{menu}</p>
</div>
<InfoTooltip tooltipText={tooltip} />
</div>
{ ThermalExpandOption && (
<GetExpandedMenu menuName={menu} decorator={props.decorator} />
)}
{ SurfaceExpandOption && (
<GetExpandedMenu menuName={menu} decorator={props.decorator} />
)}
{ ContourExpandOption && (
<GetExpandedMenu menuName={menu} decorator={props.decorator} />
)}
{ CloudExpandOption && (
<GetExpandedMenu menuName={menu} decorator={props.decorator} />
)}
{ FlowlinesExpandOption && (
<GetExpandedMenu menuName={menu} decorator={props.decorator} />
)}
</div>
);
};
export default MenuCard;
Lift state up.
If state of your item depends on state of menu item next to it, you can refactor both to depend on the state from "menu" container. Something like "openedItem" state.
You can find detailed instructions in React docs here:
https://reactjs.org/docs/lifting-state-up.html ,
with examples.