【问题标题】:<Outlet /> fails to rerender with react router v6<Outlet /> 无法使用反应路由器 v6 重新渲染
【发布时间】:2022-07-26 15:36:01
【问题描述】:

在下面的代码中,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>
        )
    }
}

【问题讨论】:

  • 您确定在登录页面加载时在路由器状态下定义了团队吗?因此,当您浏览团队页面/链接时不是这样。
  • @CasperKuethe 当我点击第一个按钮时,它会正确加载,即 url 是 /team1 并且会显示 team1 的内容。但是之后点击按钮会更改 url 但不会更改内容
  • 目前还不清楚这里有什么问题。您能否提供一个 running 代码和框演示来重现我们可以现场检查和调试的这个问题?但是,在映射的 Route 组件上 缺少一个 React 键。
  • @DrewReese 创建沙盒的过程引导我修复它 --- 当我从 BaseTeam 组件中删除构造函数并正确呈现 this.props.name 时,问题得到解决。不知道为什么会这样。查看沙箱以查看非功能版本codesandbox.io/s/blue-silence-8svo9v?file=/src/baseteam.js

标签: reactjs react-router react-router-dom


【解决方案1】:

映射的路由似乎缺少一个 React 键。添加key={path},这样每条路由都会呈现BaseTeam 的不同实例。

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

它应该指定一个key 属性,以便在密钥更改时重新安装BaseTeam 并设置name 类属性。

例子:

<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 反模式。如您所见,它需要额外的代码来保持 props 和 state 同步。

【讨论】:

    【解决方案2】:

    可能会向反应库发出信号,表明密钥已更改,因此需要重新渲染出口

    const LandingPage = () => {
        const location = useLocation(); // react-router-dom
        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 key={location.pathname}/>
            </div>
        )}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-08-03
      • 2019-03-02
      • 2018-01-05
      • 2022-08-02
      • 1970-01-01
      • 2020-07-05
      • 2019-04-25
      • 1970-01-01
      相关资源
      最近更新 更多