Reputation: 133
How can I get all states of children from parent element?
I created a page, and there are a few elements, the most important is this component list.
Here is the parent element:
const Home = () => {
const walls = [1, 2, 3, 4];
return (
<Layout>
{walls.map(wall => {
return <Wall key={wall} index={wall} />;
})}
</Layout>
);
};
As you can see, it generates a list of elements with map.
So, how can I get all children states from parent element?
This is the child component:
const Wall = ({ index }: IWall) => {
const { doors, windows, handleWindows, handleDoors } =
useWall();
return (
<div>
<input .../>
<input .../>
...
</div>
);
};
And it's hooks:
export const useWall = () => {
const [doors, setDoors] = useState(0);
const [windows, setWindows] = useState(0);
const handleWindows = (value: number) => {
if (value < 0 || value > 50) return;
setWindows(value);
};
const handleDoors = (value: number) => {
if (value < 0 || value > 50) return;
setDoors(value);
};
return { doors, windows, handleWindows, handleDoors };
};
Upvotes: 2
Views: 558
Reputation: 203466
It's generally considered a React anti-pattern for parent components to reach into children components to access state and functions. The solution is to Lift State Up to the parent component and pass the state and state update callbacks as props down to children components.
Example:
const Home = () => {
const [walls, setWalls] = useState<IWall[]>(
[1, 2, 3, 4].map((id) => ({
id,
doors: 0,
windows: 0
}))
);
const changeHandler = (id: number) => (
e: React.ChangeEvent<HTMLInputElement>
) => {
const { name, value } = e.target;
if (Number(value) >= 0 && Number(value) <= 50) {
setWalls((walls) =>
walls.map((wall) =>
wall.id === id ? { ...wall, [name]: value } : wall
)
);
}
};
return (
<Layout>
{walls.map((wall) => {
return (
<Wall
key={wall.id}
wall={wall}
changeHandler={changeHandler(wall.id)}
/>
);
})}
</Layout>
);
};
...
interface IWall {
id: number;
doors: number;
windows: number;
}
interface WallProps {
wall: IWall;
changeHandler: React.ChangeEventHandler<HTMLInputElement>;
}
const Wall = ({ changeHandler, wall }: WallProps) => {
return (
<div>
<h2>Wall: {wall.id}</h2>
<label>
Doors
<input
name="doors"
type="number"
value={wall.doors}
onChange={changeHandler}
/>
</label>
<label>
Windows
<input
name="windows"
type="number"
value={wall.windows}
onChange={changeHandler}
/>
</label>
</div>
);
};
Upvotes: 2