【问题标题】:Trigger a rerender of parent component when a child component is rendered子组件渲染时触发父组件的重新渲染
【发布时间】:2021-12-01 19:53:00
【问题描述】:

我正在使用以下 material-ui 主题 Paperbase 并在 Header.js 组件中,我有以下 useEffect 钩子:

const [temperature, setTemperature] = useState([]);

  const getTemperature= async () => {
    try {

      const response = await fetch('/get-temperature')
      const tempData = await response.json();

      setTemperature(tempData);
    } catch (err) {
      console.error(err.message);
    }
  };

useEffect(() => {
    getTemperature();
}, []);  

这样做的主要目的是将当前温度显示为信息,在标题组件中,该组件在第一页加载/渲染时显示。

现在在下面的 App.js 中,我有以下 return 设置,其中调用了上述 Header 组件。

return (
    <Router>
      <UserProvider myinfo={myinfo}>
        <Switch>
          <Route path="/">
              <ThemeProvider theme={theme}>
                <div className={classes.root}>
                  <CssBaseline />
                  <nav className={classes.drawer}>
                    <Hidden xsDown implementation="css">
                      <Navigator />
                    </Hidden>
                  </nav>
                  <div className={classes.app}>
                    <Header
                      onDrawerToggle={handleDrawerToggle}
                    />
                    <main className={classes.main}>
                      <Switch>
                        <Route exact path="/new-user"
                          render={(props) => <Content key={props.location.key} />}
                        />
                        <Route exact path="/view-results"
                          render={(props) => <ViewResults key={props.location.key} />}
                        />
                      </Switch>
                    </main>
                  </div>
                </div>
              </ThemeProvider>
          </Route>
        </Switch>
      </UserProvider>
    </Router>
);

我的问题是,当用户路由到 /new-user/view-results 进而调用 Content.jsViewResults.js 时,我如何触发 Header(父级)的重新渲染,以便使Header.js 中的useEffect 刷新数据,从 REST api 获取并再次在 header 中显示最新的温度?

理想情况下,无论何时呈现 Content.jsViewResults.js,请确保调用 Header.js getTemperature()

任何帮助将不胜感激。

【问题讨论】:

  • 您在构建组件和路由时遇到问题。 应该只包含 并且您的 Header 应该在路由内部并且能够捕获路径。你需要的是一个布局实现。
  • @ThanhTrung - 我相信这是一个错字。如果仍然不正确,非常感谢您的帮助以解决我的重新渲染问题。
  • 就像我说的,Header 必须是 Route 的后代。否则你需要把你的 useEffect 放在 Content 和 ViewResult 中。然后触发一个回调到 Router 以传递 Header。检查这个dev.to/selvaece25/multiple-layout-in-react-router-3acb
  • @ThanhTrung - 请查看更新的 设置,其中我的
    现在是 Route 的后代。不幸的是,当用户输入/new-user/view-results 时,我仍然不确定如何触发
    的重新渲染。任何帮助都会很棒。

标签: javascript reactjs react-hooks state rerender


【解决方案1】:

您当前的代码非常接近多布局系统。作为Route 的子组件,您可以通过useLocation() 甚至原生的window.location.pathname 访问当前位置。

这是我的多布局 React 应用示例。您可以尝试使用它来适应您的代码。

MainLayout 在未指定 path 时使用回退路由。它还包含一个Header 并包含一个页面

const Dispatcher = () => {
    const history = useHistory();

    history.push('/home');

    return null;
};

const App = () => (
    <BrowserRouter>
        <Switch>
            <Route
                component={Dispatcher}
                exact
                path="/"
            />

            <Route
                exact
                path="/login/:path?"
            >
                <LoginLayout>
                    <Switch>
                        <Route
                            component={LoginPage}
                            path="/login"
                        />
                    </Switch>
                </LoginLayout>
            </Route>

            <Route>
                <MainLayout>
                    <Switch>
                        <Route
                            component={HomePage}
                            path="/home"
                        />
                    </Switch>
                </MainLayout>
            </Route>
        </Switch>
    </BrowserRouter>
);

这是MainLayout的代码

const MainLayout = ({ children }) => (
    <Container
        disableGutters
        maxWidth={false}
    >
        <Header location={props.location} />

        <Container
            component="main"
            maxWidth={false}
            sx={styles.main}
        >
            {children}
        </Container>

        <Footer />
    </Container>
);

现在Header 可以是任何东西。您需要在此组件中放置一个捕获

import { useLocation } from 'react-router-dom'

cont Header = (props) => {
  const { pathname } = useLocation();
  
  //alternatively you can access props.location
  
  useEffect(() => {
    if (pathname === '/new-user') {
      getTemperature();
    }
  }, [pathname]);  
};

请注意,Header 不是Route 的直接后代,因此它不能通过props 直接访问该位置。你需要链式转账

Route -> MainLayout -> Header

或者更好地使用useLocation

【讨论】: