如何在 react-router-dom 中使用 Forwarding Refs
How to use Forwarding Refs with react-router-dom
我已经理解 Forwarding Refs 和 react-router-dom 的概念了。但是在这个实现中,我不确定如何正确使用它。
我有一个子组件,其中有一个在 useState 中设置 null 的函数。
我希望每次单击呈现此子组件的菜单项时都执行此功能。
该菜单挂载在App中的com List和Router中,如下3个文件所示。
准确地说,我不知道将useRef放在哪里执行子函数resetMyState,如果它在App.js或或AppBarAndDrawer.js以及如何做。
childComponent.js
...
const MeusAnuncios = forwardRef((props, ref) => {
const [myState, setMyState] = useState(null);
function resetMyState(){
setMyState(null)
}
async function chargeMyState() {
await
...
setMyState(values)
...
}
...
AppBarAndDrawer.js
...
const drawer = (
<div>
<div className={classes.toolbar} />
<Divider />
<List>
{[
{ label: "Minha Conta", text: "minhaConta", icon: "person" },
{ label: "Novo Anúncio", text: "novoAnuncio", icon: "queue_play_next" },
{ label: "Meus Anúncios", text: "meusAnuncios", icon: "dvr" },
{ label: "Estatísticas", text: "estatisticas", icon: "line_style" },
{ label: "Faturamento", text: "faturamento", icon: "local_atm" },
{ label: "childComponent", text: "childComponent", icon: "notifications" },
].map(({ label, text, icon }, index) => (
<ListItem
component={RouterLink}
selected={pathname === `/${text}`}
to={`/${text}`}
button
key={text}
disabled={text !=='minhaConta' && !cadCompleto ? true : false}
onClick={() => {click(text) }}
>
<ListItemIcon>
<Icon>{icon}</Icon>
</ListItemIcon>
<ListItemText primary={label.toUpperCase()} />
</ListItem>
))}
</List>
<Divider />
</div>
);
return(
...
{drawer}
...
)
...
App.js
...
export default function App() {
const childRef = useRef();
...
<Router>
<AppBarAndDrawer/>
<Switch>
<Route path="/childComponent">
<childComponent />
</Route>
...
...
您创建的 ref
确实需要驻留在一个共同的祖先中,即 App
,因此它和回调可以传递给 children 组件。 ref
到 ChildComponent
和 AppBarAndDrawer
的回调。此外,ChildComponent
将需要使用 useImperativeHandle 挂钩来公开 child 的 resetMyState
处理程序。
MeusAnuncios
使用 useImperativeHandle
挂钩公开 resetMyState
处理程序。
const MeusAnuncios = forwardRef((props, ref) => {
const [myState, setMyState] = useState(null);
function resetMyState(){
setMyState(null);
}
useImperativeHandle(ref, () => ({
resetMyState,
}));
async function chargeMyState() {
await
...
setMyState(values)
...
}
...
});
应用
创建一个 resetChildState
回调并将 ref 传递给 child 组件并将回调传递给 AppBarAndDrawer
组件。
export default function App() {
const childRef = useRef();
const resetChildState = () => {
if (childRef.current.resetMyState) {
childRef.current.resetMyState();
}
};
...
<Router>
<AppBarAndDrawer onClick={resetChildState} /> // <-- pass callback
<Switch>
<Route path="/childComponent">
<ChildComponent ref={childRef} /> // <-- pass ref
</Route>
...
</Switch>
...
</Router>
}
AppBarAndDrawer
消费并调用传递的回调。
const AppBarAndDrawer = ({ onClick }) => { // <-- destructure callback
...
const drawer = (
<div>
...
<List>
{[
...
].map(({ label, text, icon }, index) => (
<ListItem
component={RouterLink}
selected={pathname === `/${text}`}
to={`/${text}`}
button
key={text}
disabled={text !=='minhaConta' && !cadCompleto}
onClick={() => {
click(text);
onClick(); // <-- call callback here
}}
>
<ListItemIcon>
<Icon>{icon}</Icon>
</ListItemIcon>
<ListItemText primary={label.toUpperCase()} />
</ListItem>
))}
</List>
...
</div>
);
...
};
我已经理解 Forwarding Refs 和 react-router-dom 的概念了。但是在这个实现中,我不确定如何正确使用它。 我有一个子组件,其中有一个在 useState 中设置 null 的函数。 我希望每次单击呈现此子组件的菜单项时都执行此功能。 该菜单挂载在App中的com List和Router中,如下3个文件所示。 准确地说,我不知道将useRef放在哪里执行子函数resetMyState,如果它在App.js或或AppBarAndDrawer.js以及如何做。
childComponent.js
...
const MeusAnuncios = forwardRef((props, ref) => {
const [myState, setMyState] = useState(null);
function resetMyState(){
setMyState(null)
}
async function chargeMyState() {
await
...
setMyState(values)
...
}
...
AppBarAndDrawer.js
...
const drawer = (
<div>
<div className={classes.toolbar} />
<Divider />
<List>
{[
{ label: "Minha Conta", text: "minhaConta", icon: "person" },
{ label: "Novo Anúncio", text: "novoAnuncio", icon: "queue_play_next" },
{ label: "Meus Anúncios", text: "meusAnuncios", icon: "dvr" },
{ label: "Estatísticas", text: "estatisticas", icon: "line_style" },
{ label: "Faturamento", text: "faturamento", icon: "local_atm" },
{ label: "childComponent", text: "childComponent", icon: "notifications" },
].map(({ label, text, icon }, index) => (
<ListItem
component={RouterLink}
selected={pathname === `/${text}`}
to={`/${text}`}
button
key={text}
disabled={text !=='minhaConta' && !cadCompleto ? true : false}
onClick={() => {click(text) }}
>
<ListItemIcon>
<Icon>{icon}</Icon>
</ListItemIcon>
<ListItemText primary={label.toUpperCase()} />
</ListItem>
))}
</List>
<Divider />
</div>
);
return(
...
{drawer}
...
)
...
App.js
...
export default function App() {
const childRef = useRef();
...
<Router>
<AppBarAndDrawer/>
<Switch>
<Route path="/childComponent">
<childComponent />
</Route>
...
...
您创建的 ref
确实需要驻留在一个共同的祖先中,即 App
,因此它和回调可以传递给 children 组件。 ref
到 ChildComponent
和 AppBarAndDrawer
的回调。此外,ChildComponent
将需要使用 useImperativeHandle 挂钩来公开 child 的 resetMyState
处理程序。
MeusAnuncios
使用 useImperativeHandle
挂钩公开 resetMyState
处理程序。
const MeusAnuncios = forwardRef((props, ref) => {
const [myState, setMyState] = useState(null);
function resetMyState(){
setMyState(null);
}
useImperativeHandle(ref, () => ({
resetMyState,
}));
async function chargeMyState() {
await
...
setMyState(values)
...
}
...
});
应用
创建一个 resetChildState
回调并将 ref 传递给 child 组件并将回调传递给 AppBarAndDrawer
组件。
export default function App() {
const childRef = useRef();
const resetChildState = () => {
if (childRef.current.resetMyState) {
childRef.current.resetMyState();
}
};
...
<Router>
<AppBarAndDrawer onClick={resetChildState} /> // <-- pass callback
<Switch>
<Route path="/childComponent">
<ChildComponent ref={childRef} /> // <-- pass ref
</Route>
...
</Switch>
...
</Router>
}
AppBarAndDrawer
消费并调用传递的回调。
const AppBarAndDrawer = ({ onClick }) => { // <-- destructure callback
...
const drawer = (
<div>
...
<List>
{[
...
].map(({ label, text, icon }, index) => (
<ListItem
component={RouterLink}
selected={pathname === `/${text}`}
to={`/${text}`}
button
key={text}
disabled={text !=='minhaConta' && !cadCompleto}
onClick={() => {
click(text);
onClick(); // <-- call callback here
}}
>
<ListItemIcon>
<Icon>{icon}</Icon>
</ListItemIcon>
<ListItemText primary={label.toUpperCase()} />
</ListItem>
))}
</List>
...
</div>
);
...
};