<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 将传递的道具存储到本地状态。如您所见,它需要额外的代码来保持道具和状态同步。
在下面的代码中,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 将传递的道具存储到本地状态。如您所见,它需要额外的代码来保持道具和状态同步。