I have a nested plan list. And I want to add plans and display it using recoil. But I don't need to add the name attribute but only plans by inputs.
import React, { useState } from "react";
import "./styles.css";
import { RecoilRoot, atom, useRecoilState } from "recoil";
const todoListState = atom({
key: "TodoList",
default: {
name: "Lee",
plans: [
{
plan: "",
price: ""
}
]
}
});
export function TodoApp() {
const [list, setList] = useRecoilState(todoListState);
const [input, setInput] = useState({
plan: "",
price: ""
});
const handleChange = (e) => {
setInput({
...input,
[e.target.name]: e.target.value
});
};
const handleClick = async (e) => {
e.preventDefault();
setList({
plan: input.plan,
price: parseInt(input.price)
});
setInput({
plan: "",
price: ""
});
};
return (
<>
<div>Plans</div>
{list.plans.map((x, i) => {
return (
<div key={i}>
<div>{x.plan}</div>
<div>{x.price}</div>
</div>
);
})}
<div>
<label htmlFor="plan">plan</label>
<input
type="text"
value={input.plan}
onChange={handleChange}
name="plan"
/>
</div>
<div>
<label htmlFor="price">price</label>
<input
type="text"
value={input.price}
onChange={handleChange}
name="price"
/>
</div>
<button onClick={handleClick}>Add Item</button>
</>
);
}
export default function App() {
return (
<RecoilRoot>
<div className="App">
<TodoApp />
</div>
</RecoilRoot>
);
}
To implement this, what do I need to use or fix? The code is below:
https://codesandbox.io/embed/nested-arrays-forked-49idv?fontsize=14&hidenavigation=1&theme=dark
You just need to refactor your click handler so that when you update your recoil atom, you spread in the existing parts of the object, effectively appending to the array:
const handleClick = async (e) => {
e.preventDefault();
setList(list => ({
...list,
plans: [
...list.plans,
{
plan: input.plan,
price: parseInt(input.price),
},
],
}));
setInput({plan: "", price: ""});
};