如何在 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 组件。 refChildComponentAppBarAndDrawer 的回调。此外,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>
  );

  ...
};