<Outlet /> 无法使用 React Router v6 重新渲染

<Outlet /> fails to rerender with react router v6

在下面的代码中,url 发生了变化,但内容在手动刷新之前不会重新呈现。我在这里做错了什么?我可以使用 props.children 或其他东西,但我真的不想这样做。我的理解是应该渲染.

下嵌套元素的内容
const LandingPage = () => {
        return (
            <div>
                <div>
                    buttons
                    <Button>
                        <Link to="/team1">team1</Link>
                    </Button>
                    <Button>
                        <Link to="/team2">team2</Link>
                    </Button>
                    <Button>
                        <Link to="/team3">team3</Link>
                    </Button>
                </div>
                <Outlet />
            </div>
        )
}

export default class Router extends Component<any> {

    state = {
        teams: [team1, team2, team3] as Team[]
    }

    public render() {
        return (
            <BrowserRouter>
                <Routes>
                    <Route path='/' element={<LandingPage />} >
                        {
                            this.state.teams.map(team => {
                                const path = `/${team.name.toLowerCase()}`
                                return (
                                    <Route path={path} element={
                                        <BaseTeam
                                            name={team.name}
                                            TL={team.TL}
                                            location={team.location}
                                            members={team.members}
                                            iconPath={team.iconPath}
                                        />
                                    } />)
                            })
                        }
                    </Route>
                </Routes>
            </BrowserRouter>
        )
    }
}

映射的路由似乎缺少 React 密钥。添加 key={path} 以便每条路线呈现 BaseTeam.

的不同实例

主要问题是 BaseTeam 组件对于呈现它的所有路由都是同一个“实例”。

它应该 有一个 key 指定的道具,所以当键改变时 BaseTeam 被重新安装并设置 name class 属性.

示例:

<BrowserRouter>
  <Routes>
    <Route path="/" element={<LandingPage />}>
      {this.state.teams.map((team) => {
        const path = `/${team.name.toLowerCase()}`;
        return (
          <Route
            key={path} // <-- add missing React key
            path={path}
            element={(
              <BaseTeam
                key={path} // <-- add key to trigger remounting
                name={team.name}
              />
            )}
          />
        );
      })}
    </Route>
  </Routes>
</BrowserRouter>

BaseTeam 需要更新以响应 name 道具更新。使用 componentDidUpdate 生命周期方法根据当前状态检查 name 道具,需要排队状态更新。

示例:

class BaseTeam extends React.Component {
  state = {
    name: this.props.name
  };

  componentDidUpdate(prevProps) {
    if (prevProps.name !== this.props.name) {
      this.setState({ name: this.props.name });
    }
  }

  render() {
    return <div>{this.state.name}</div>;
  }
}

...

<BrowserRouter>
  <Routes>
    <Route path="/" element={<LandingPage />}>
      {this.state.teams.map((team) => {
        const path = `/${team.name.toLowerCase()}`;
        return (
          <Route
            key={path}
            path={path}
            element={<BaseTeam name={team.name} />}
          />
        );
      })}
    </Route>
  </Routes>
</BrowserRouter>

正如您在代码中发现的那样,直接渲染 props.name 道具 实际上 是正确的解决方案。这是一个 React anti-pattern 将传递的道具存储到本地状态。如您所见,它需要额外的代码来保持道具和状态同步。