React如何将子组件Selector的选中对象状态传递给父组件
实现方案
React中子组件向父组件传递数据的标准逻辑是:父组件提前将接收数据的回调函数通过props传给子组件,子组件内部数据更新时触发该回调,将需要传递的数据作为参数回传给父组件。
步骤1:修改父组件(index.js)
- 新增state存储选中的成员ID列表、群组名称
- 给子组件
Selector传入接收选中数据的回调函数 - 将群组成员输入框的value绑定为state中的选中成员列表
修改后完整代码:
import React from "react"; import ReactDOM from "react-dom"; import { TextField, Button } from "@material-ui/core"; import Selector from "./Selector"; function App() { // 新增state存储选中的成员ID、群组名称 const [selectedMembers, setSelectedMembers] = React.useState([]); const [groupName, setGroupName] = React.useState(""); const createAction = () => { // 提交时直接取groupName和selectedMembers即可 console.log("提交参数:", { groupName, members: selectedMembers }); console.log("fire up post request"); }; return ( <div> <div> <h1>Create group (parent)</h1> <form> <TextField id="name" label="Group name" variant="outlined" required={true} value={groupName} onChange={(e) => setGroupName(e.target.value)} /> <br /> <br /> <p>如何将选中值传递到此处:</p> <TextField id="members" label="Group members" variant="outlined" required={true} inputProps={{ readOnly: true }} fullWidth // 绑定选中的成员ID,用逗号分隔和子组件展示效果一致 value={selectedMembers.join(",")} /> </form> <br /> <Button variant="contained" color="primary" onClick={createAction}> Create group </Button> </div> <br /> <br /> {/* 给子组件传入接收数据的回调函数 */} <Selector onChange={setSelectedMembers} /> </div> ); } ReactDOM.render(<App />, document.querySelector("#app"));
步骤2:修改子组件(Selector.js)
- 删除无效代码行
props = selectionObj - 新增
useEffect监听内部选中状态变化,每次变化就调用父组件传入的回调,将最新选中ID列表回传 - 功能验证完成后可删除子组件底部展示选中ID的TextField
修改后完整代码:
import React from "react"; import { Box, Typography, Checkbox, TextField, Button } from "@material-ui/core"; const DATA = [ { id: "1", name: "First name" }, { id: "2", name: "Second name" }, { id: "3", name: "Third name" }, { id: "5", name: "Fourth name" }, { id: "6", name: "Fifth name" } ]; export default function Selector(props) { const [selectionObj, setSelectionObj] = React.useState({}); // 监听selectionObj变化,触发父组件传入的回调回传数据 React.useEffect(() => { props.onChange(Object.keys(selectionObj)) }, [selectionObj, props]) const onOptionSelect = (option) => (e) => { if (selectionObj[option.id]) { let duplicateSelectedObj = { ...selectionObj }; delete duplicateSelectedObj[option.id]; setSelectionObj(duplicateSelectedObj); } else setSelectionObj((prev) => ({ ...prev, ...{ [option.id]: option.name } })); }; const isAllChecked = DATA.length === Object.keys(selectionObj).length; const onCheckAllClick = () => { if (isAllChecked) { setSelectionObj({}); } else { let allSelected = {}; DATA.forEach((data) => { allSelected[data.id] = data.name; }); setSelectionObj(allSelected); } }; return ( <Box> <Typography variant="h5">Selector (child component)</Typography> <Box my={2}> {/* Table Header. */} <Box display="flex" alignItems="center" borderBottom={1}> <Box display="flex" flex={1}> <Checkbox checked={isAllChecked} indeterminate={ Object.keys(selectionObj).length > 0 && !isAllChecked } onChange={onCheckAllClick} /> </Box> <Box display="flex" flex={10}> <Typography variant="h6">Id</Typography> </Box> <Box display="flex" flex={10}> <Typography variant="h6">Name</Typography> </Box> </Box> {/* Table contents */} {DATA.map((data) => ( <Box key={data.id} display="flex" alignItems="center"> <Box display="flex" flex={1}> <Checkbox onChange={onOptionSelect(data)} checked={Boolean(selectionObj[data.id])} /> </Box> <Box display="flex" flex={10}> <Typography variant="h6">{data.id}</Typography> </Box> <Box display="flex" flex={10}> <Typography variant="h6">{data.name}</Typography> </Box> </Box> ))} </Box> <Button variant="contained" color="primary" onClick={() => console.log("Selected ids: ", Object.keys(selectionObj))} > Get Payload </Button> <br /> <br /> {/* 验证完成后可删除下方这个TextField */} <TextField value={Object.keys(selectionObj)} variant="outlined" inputProps={{ readOnly: true }} fullWidth /> </Box> ); }
修改完成后,子组件每次勾选、取消勾选、全选/反选操作,都会同步将选中的用户ID列表回传给父组件,父组件的群组成员输入框会自动同步展示内容,提交表单时直接使用父组件内存储的groupName和selectedMembers即可。
内容的提问来源于stack exchange,提问作者Ydonut13
相关产品推荐
相关产品推荐

