I have this object that can have multiple values inside:
const [sort, setSort] = useState({
"city": [],
"price": [],
"year": []
});
When you click "add", I want "city" to have this value for example: ["Los Angeles"]
or both ["Los Angeles", "New York"]
How can I do that?
I have tried this but it doesn't work. I'm newbie in javascript/reactjs.
import { useState, useEffect } from "react";
function Items() {
const [sort, setSort] = useState({
"city": [],
"price": [],
"year": []
});
useEffect(() => {
console.log(sort);
}, [sort])
function addItem(itemType, itemValue)
{
for (var type in sort)
{
if(type.hasOwnProperty(type))
{
if(type.toLowerCase() === itemType.toLowerCase())
{
sort.type.push(itemValue);
setSort(sort);
break;
}
}
}
}
return (
<>
<div className="item" onClick={(e) => addItem(e, "City", "Los Angeles")}>
<span>Add LA</span>
</div>
<div className="item" onClick={(e) => addItem(e, "City", "New York")}>
<span>Add NY</span>
</div>
</>
)
}
export default Items
You have a few issues:
addItem
should be a callback, so wrap it in the useCallback
hook.setSort
so that you do not need sort
as a dependencyNote: You should avoid using var
; stick with const
and let
import { useState, useEffect, useCallback } from "react";
const Items = () => {
const [sort, setSort] = useState({
city: [],
price: [],
year: []
});
useEffect(() => {
console.log(sort);
}, [sort]);
const addItem = useCallback((_event, itemType, itemValue) => {
setSort((currentSort) => {
const key = itemType.toLowerCase(),
existing = currentSort[key] ?? [];
return { ...currentSort, [key]: [...existing, itemValue] };
});
}, []);
return (
<>
<div className="item" onClick={(e) => addItem(e, "City", "Los Angeles")}>
<span>Add LA</span>
</div>
<div className="item" onClick={(e) => addItem(e, "City", "New York")}>
<span>Add NY</span>
</div>
</>
);
}
export default Items;
Here is a demo of the code above:
const { Fragment, useState, useEffect, useCallback } = React;
const Items = () => {
const [sort, setSort] = useState({
city: [],
price: [],
year: []
});
useEffect(() => {
console.log(JSON.stringify(sort));
}, [sort]);
const addItem = useCallback((_event, itemType, itemValue) => {
setSort((currentSort) => {
const key = itemType.toLowerCase(),
existing = currentSort[key] || [];
return { ...currentSort, [key]: [...existing, itemValue] };
});
}, []);
return (
<Fragment>
<div className="item" onClick={(e) => addItem(e, "City", "Los Angeles")}>
<span>Add LA</span>
</div>
<div className="item" onClick={(e) => addItem(e, "City", "New York")}>
<span>Add NY</span>
</div>
</Fragment>
);
};
const App = () => (
<div>
<Items />
</div>
);
ReactDOM
.createRoot(document.getElementById('root'))
.render(<App />);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>
Here is an example of not allowing duplicates. Just use the Set
object to store the existing array, modify it, and convert it back into an array.
const { Fragment, useState, useEffect, useCallback } = React;
const Items = () => {
const [sort, setSort] = useState({
city: [],
price: [],
year: []
});
useEffect(() => {
console.log(JSON.stringify(sort));
}, [sort]);
const addItem = useCallback((_event, itemType, itemValue) => {
setSort((currentSort) => {
const key = itemType.toLowerCase(),
existing = new Set(currentSort[key] || []);
existing.add(itemValue);
return { ...currentSort, [key]: [...existing] };
});
}, []);
const removeItem = useCallback((_event, itemType, itemValue) => {
setSort((currentSort) => {
const key = itemType.toLowerCase(),
existing = new Set(currentSort[key] || []);
existing.delete(itemValue);
return { ...currentSort, [key]: [...existing] };
});
}, []);
return (
<div className="grid">
<div className="item" onClick={(e) => addItem(e, "City", "Los Angeles")}>
<span>Add LA</span>
</div>
<div className="item" onClick={(e) => addItem(e, "City", "New York")}>
<span>Add NY</span>
</div>
<div className="item" onClick={(e) => removeItem(e, "City", "Los Angeles")}>
<span>Remove LA</span>
</div>
<div className="item" onClick={(e) => removeItem(e, "City", "New York")}>
<span>Remove NY</span>
</div>
</div>
);
};
const App = () => (
<div>
<Items />
</div>
);
ReactDOM
.createRoot(document.getElementById('root'))
.render(<App />);
html, body, #root {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#root {
display: flex;
justify-content: center;
}
.grid {
display: grid;
grid-template-columns: repeat(2, auto);
grid-row-gap: 0.5rem;
grid-column-gap: 2rem;
}
.item {
display: flex;
justify-content: center;
align-items: center;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>