在我的应用中,我有一个RoomsContainer
父组件,其中有Room
个子组件数组。在Room
中,我希望有一个按钮,可以通过调用父组件的Room
函数来向RoomsContainer
添加其他addRoom
元素。
这就是我所拥有的:
function RoomsContainer() {
const [rooms, setRooms] = useState([]);
const addRoom = () => {
var uniqid = require('uniqid');
let key = uniqid("room-");
setRooms([
...rooms,
<Room
key={key}
id={key}
addRoom={addRoom}
removeRoom={removeRoom}
/>
]);
console.log(rooms);
}
useEffect(() => {
addRoom();
}, []);
// ...
return (
<div id="room-wrapper">
{rooms}
</div>
)
}
function Room(props) {
// ...
return (
<button onClick={props.addRoom}>
Add room
</button>
)
}
这会添加页面加载的第一个房间,但是当我单击Add Room
组件中的Room
按钮时,它不会添加任何其他房间。单击它似乎还可以使用新的RoomsContainer
元素完全重新渲染整个Room
组件,而不用修改其状态。而且console.log(rooms)
总是显示一个空数组,即使在设置后也是如此。
答案 0 :(得分:1)
您的addRoom函数中有一个stale closure,我认为您不应该将jsx保存到本地状态。以下应该起作用:
const id = ((id) => () => ++id)(0);
function RoomsContainer() {
const [rooms, setRooms] = React.useState([]);
//not sure why you want to use require in a react app
//var uniqid = require('uniqid');
//use React.useCallback so this function never changes
const addRoom = React.useCallback(
//setRooms takes a callback function that receives the current rooms
// only store the id in rooms, not the jsx
() => setRooms((rooms) => [...rooms, id()]),
[]
);
const removeRoom = React.useCallback(
//setRooms takes a callback function that receives the current rooms
// only store the id in rooms, not the jsx
(id) =>
setRooms((rooms) =>
rooms.filter((room) => room !== id)
),
[]
);
React.useEffect(() => {
addRoom();
}, [addRoom]);
return (
// do not use id in html elements, id should be unique
// in the DOM but you can't/shouldn't guarantee that your app doesn't
// have multiple RoomContainer elements
<ul>
{rooms.map((id) => (
<Room
key={id}
id={id}
addRoom={addRoom}
removeRoom={removeRoom}
/>
))}
</ul>
);
}
//make Room a pure component so there are no needless re renders
const Room = React.memo(function Room({
addRoom,
removeRoom,
id,
}) {
return (
<li>
<button onClick={addRoom}>Add room</button>
<button onClick={() => removeRoom(id)}>
Remove room {id}
</button>
</li>
);
});
ReactDOM.render(
<RoomsContainer />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
答案 1 :(得分:1)
console.log(rooms);
最初显示一个空数组是正常的,因为设置状态是异步的。
这是您应该做的:
function RoomsContainer() {
const [rooms, setRooms] = useState([]);
const addRoom = useCallback(() => {
var uniqid = require("uniqid");
let key = uniqid("room-");
setRooms(rooms => [...rooms, key]);
}, []);
useEffect(() => {
addRoom();
}, []);
return (
<div id="room-wrapper">
{rooms.map((key) => {
return <Room key={key} id={key} addRoom={addRoom} />;
})}
</div>
);
}