Material UI: 如何访问子组件函数?
Material UI: How to access a child component function?
我正在使用 Material UI
创建带有 React
的应用程序。我有一个 Dialog
允许用户更改有关对象的一系列信息(请参见下面的代码)。有两个不同的按钮。每个按钮指向一个不同的对象。因此,根据用户想要更改的对象,使用不同的参数调用 onDialogOpen
函数。一切正常。
export default function CollectingFormInput() {
const [dialogOpen, setDialogOpen] = useState(false);
const [snackbarOpen, setSnackbarOpen] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState('');
const [name, setName] = useState("");
const [alias, setAlias] = useState("");
const [latitude, setLatitude] = useState("");
const [longitude, setLongitude] = useState("");
const [address, setAddress] = useState("");
const [notes, setNotes] = useState("");
const onDialogOpen = (info) => {
setName(info.name);
setAlias(info.alias);
setLatitude(info.latitude);
setLongitude(info.longitude);
setAddress(info.address);
setNotes(info.notes);
setDialogOpen(true);
};
const onDialogClose = () => {
setDialogOpen(false);
};
const onSnackbarClose = (e, reason) => {
if (reason === 'clickaway') {
return;
}
setSnackbarOpen(false);
setSnackbarMessage('');
};
const onCreate = () => {
setSnackbarOpen(true);
setSnackbarMessage(`Dados de ${name} atualizados!`);
onDialogClose();
};
return (
<Fragment>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_01",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 1
</Button>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_02",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 2
</Button>
<Dialog open={dialogOpen} onClose={onDialogClose}>
<DialogTitle>Editar informações da estação</DialogTitle>
<DialogContent>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-name"
id="outlined-read-only-input"
label="Nome"
defaultValue={name}
size="small" fullWidth
InputProps={{
readOnly: true,
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-alias"
id="outlined-basic"
label="Apelido"
InputProps={{ name: 'alias' }}
onChange={field => setAlias(field.target.value)}
value={alias}
defaultValue=""
size="small" fullWidth
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-latitude"
id="outlined-basic"
label="Latitude"
InputProps={{ name: 'latitude' }}
onChange={field => setLatitude(field.target.value)}
value={latitude}
defaultValue=""
size="small"
fullWidth
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-longitude"
id="outlined-basic"
label="Longitude"
InputProps={{ name: 'longitude' }}
onChange={field => setLongitude(field.target.value)}
value={longitude}
defaultValue=""
size="small"
fullWidth
/>
</Grid>
</Grid>
<TextField
margin="normal"
id="station-address"
id="outlined-basic"
label="Endereço"
InputProps={{ name: 'address' }}
onChange={field => setAddress(field.target.value)}
value={address}
defaultValue=""
size="small"
fullWidth
/>
<TextField
margin="normal"
id="station-obs"
id="outlined-multiline-flexible"
multiline
maxRows={4}
label="Observações"
InputProps={{ name: 'notes' }}
onChange={field => setNotes(field.target.value)}
value={notes}
defaultValue=""
size="small"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={onDialogClose} color="primary">Cancelar</Button>
<Button
variant="contained"
onClick={onCreate}
color="primary"
>
Salvar
</Button>
</DialogActions>
</Dialog>
<Snackbar
open={snackbarOpen}
message={snackbarMessage}
onClose={onSnackbarClose}
autoHideDuration={4000}
/>
</Fragment>
);
}
现在,我想清理代码并创建一个独立于这两个按钮的新 CollectingFormInput
组件。所以我的代码会是这样的...
<Fragment>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_01",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 1
</Button>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_02",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 2
</Button>
<CollectingFormInput />
<Fragment>
我认为onDialogOpen
必须属于CollectingFormInput
组件并被父组件调用。
我进行了搜索,但找不到从父组件访问 onDialogOpen
的方法。有人可以帮助我吗?
您可以使用 useImperativeHanlde hook and forwardRef 钩子将子组件中的一些方法暴露给父组件。
- 将
CollectingFormInput
包裹在 forwardRef
中。并使用 useImperativeHanlde
钩子来公开其中的方法,如下所示。
import { forwardRef, useImperativeHandle } from "react";
const CollectingFormInput = forwardRef((props, ref) => {
...
...
...
const onDialogOpen = (info) => {
setName(info.name);
setAlias(info.alias);
setLatitude(info.latitude);
setLongitude(info.longitude);
setAddress(info.address);
setNotes(info.notes);
setDialogOpen(true);
};
const onDialogClose = () => {
setDialogOpen(false);
};
useImperativeHandle(ref, () => ({
onDialogOpen: onDialogOpen,
onDialogClose: onDialogClose
}));
...
...
return (
...
...
);
});
- 在父组件中创建一个 ref 并将其传递给
CollectingFormInput
以使用您在组件中公开的函数进行初始化。在执行 null / undefined 检查后调用方法。
import { useRef } from "react";
const ParentComp = () => {
const dialogHandleRef = useRef(null);
return (
<Fragment>
<Button
color="primary"
onClick={() =>
dialogHandleRef &&
dialogHandleRef?.current?.onDialogOpen({
name: "JAF_01",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})
}
>
Botão 1
</Button>
<Button
color="primary"
onClick={() =>
dialogHandleRef &&
dialogHandleRef?.current?.onDialogOpen({
name: "JAF_02",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})
}
>
Botão 2
</Button>
<CollectingFormInput ref={dialogHandleRef} />
</Fragment>
);
};
我正在使用 Material UI
创建带有 React
的应用程序。我有一个 Dialog
允许用户更改有关对象的一系列信息(请参见下面的代码)。有两个不同的按钮。每个按钮指向一个不同的对象。因此,根据用户想要更改的对象,使用不同的参数调用 onDialogOpen
函数。一切正常。
export default function CollectingFormInput() {
const [dialogOpen, setDialogOpen] = useState(false);
const [snackbarOpen, setSnackbarOpen] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState('');
const [name, setName] = useState("");
const [alias, setAlias] = useState("");
const [latitude, setLatitude] = useState("");
const [longitude, setLongitude] = useState("");
const [address, setAddress] = useState("");
const [notes, setNotes] = useState("");
const onDialogOpen = (info) => {
setName(info.name);
setAlias(info.alias);
setLatitude(info.latitude);
setLongitude(info.longitude);
setAddress(info.address);
setNotes(info.notes);
setDialogOpen(true);
};
const onDialogClose = () => {
setDialogOpen(false);
};
const onSnackbarClose = (e, reason) => {
if (reason === 'clickaway') {
return;
}
setSnackbarOpen(false);
setSnackbarMessage('');
};
const onCreate = () => {
setSnackbarOpen(true);
setSnackbarMessage(`Dados de ${name} atualizados!`);
onDialogClose();
};
return (
<Fragment>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_01",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 1
</Button>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_02",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 2
</Button>
<Dialog open={dialogOpen} onClose={onDialogClose}>
<DialogTitle>Editar informações da estação</DialogTitle>
<DialogContent>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-name"
id="outlined-read-only-input"
label="Nome"
defaultValue={name}
size="small" fullWidth
InputProps={{
readOnly: true,
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-alias"
id="outlined-basic"
label="Apelido"
InputProps={{ name: 'alias' }}
onChange={field => setAlias(field.target.value)}
value={alias}
defaultValue=""
size="small" fullWidth
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-latitude"
id="outlined-basic"
label="Latitude"
InputProps={{ name: 'latitude' }}
onChange={field => setLatitude(field.target.value)}
value={latitude}
defaultValue=""
size="small"
fullWidth
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-longitude"
id="outlined-basic"
label="Longitude"
InputProps={{ name: 'longitude' }}
onChange={field => setLongitude(field.target.value)}
value={longitude}
defaultValue=""
size="small"
fullWidth
/>
</Grid>
</Grid>
<TextField
margin="normal"
id="station-address"
id="outlined-basic"
label="Endereço"
InputProps={{ name: 'address' }}
onChange={field => setAddress(field.target.value)}
value={address}
defaultValue=""
size="small"
fullWidth
/>
<TextField
margin="normal"
id="station-obs"
id="outlined-multiline-flexible"
multiline
maxRows={4}
label="Observações"
InputProps={{ name: 'notes' }}
onChange={field => setNotes(field.target.value)}
value={notes}
defaultValue=""
size="small"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={onDialogClose} color="primary">Cancelar</Button>
<Button
variant="contained"
onClick={onCreate}
color="primary"
>
Salvar
</Button>
</DialogActions>
</Dialog>
<Snackbar
open={snackbarOpen}
message={snackbarMessage}
onClose={onSnackbarClose}
autoHideDuration={4000}
/>
</Fragment>
);
}
现在,我想清理代码并创建一个独立于这两个按钮的新 CollectingFormInput
组件。所以我的代码会是这样的...
<Fragment>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_01",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 1
</Button>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_02",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 2
</Button>
<CollectingFormInput />
<Fragment>
我认为onDialogOpen
必须属于CollectingFormInput
组件并被父组件调用。
我进行了搜索,但找不到从父组件访问 onDialogOpen
的方法。有人可以帮助我吗?
您可以使用 useImperativeHanlde hook and forwardRef 钩子将子组件中的一些方法暴露给父组件。
- 将
CollectingFormInput
包裹在forwardRef
中。并使用useImperativeHanlde
钩子来公开其中的方法,如下所示。
import { forwardRef, useImperativeHandle } from "react";
const CollectingFormInput = forwardRef((props, ref) => {
...
...
...
const onDialogOpen = (info) => {
setName(info.name);
setAlias(info.alias);
setLatitude(info.latitude);
setLongitude(info.longitude);
setAddress(info.address);
setNotes(info.notes);
setDialogOpen(true);
};
const onDialogClose = () => {
setDialogOpen(false);
};
useImperativeHandle(ref, () => ({
onDialogOpen: onDialogOpen,
onDialogClose: onDialogClose
}));
...
...
return (
...
...
);
});
- 在父组件中创建一个 ref 并将其传递给
CollectingFormInput
以使用您在组件中公开的函数进行初始化。在执行 null / undefined 检查后调用方法。
import { useRef } from "react";
const ParentComp = () => {
const dialogHandleRef = useRef(null);
return (
<Fragment>
<Button
color="primary"
onClick={() =>
dialogHandleRef &&
dialogHandleRef?.current?.onDialogOpen({
name: "JAF_01",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})
}
>
Botão 1
</Button>
<Button
color="primary"
onClick={() =>
dialogHandleRef &&
dialogHandleRef?.current?.onDialogOpen({
name: "JAF_02",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})
}
>
Botão 2
</Button>
<CollectingFormInput ref={dialogHandleRef} />
</Fragment>
);
};