我有这个用于管理身份验证的 privateRoute 组件:
const PrivateRoute = ({ component: Component, auth, ...rest }) => {
// This gets logged twice when I navigate in the app
// Using history.push("/url")
// And gets logged once when I type the url and hit enter on the browser
console.log(
"===============INSIDE PrivateRoute Component========================"
);
return (
<Route
{...rest}
render={(props) =>
auth.isAuthenticated === true ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
}
/>
);
};
奇怪的是,当我在应用程序中导航时,这个组件会被记录两次。例如,当我点击触发此代码的按钮时:
this.props.history.push("/edit-page-after-login");
我在 App.js 中有这个:
<PrivateRoute
path="/edit-page-after-login"
component={EditProfileAfterLogin}
/>
而且我有一个在该路由中呈现的组件:
export default class EditProfileInSettings extends Component {
componentDidMount() {
console.log(
"? ~ file: EditProfileInSettings.js ~ line 5 ~ EditProfileInSettings ~ componentDidMount ~ componentDidMount"
);
}
render() {
return <div>Test</div>;
}
}
因此,当我使用 history.push
导航到该组件时,它会被记录:
==============内部私有路由组件========================
? ~ 文件:EditProfileInSettings.js ~ 第 5 行 ~ EditProfileInSettings ~
componentDidMount ~ componentDidMount
==============内部私有路由组件==========================
出于某种奇怪的原因,PrivateRoute 组件被称为 TWICE,这导致我尝试实现的逻辑出现一些问题。
但是,当我在浏览器中写入 url 并输入时,它的行为是正确的,并且只会被调用ONCE:
<块引用>==============内部私有路由组件========================
? ~ 文件:EditProfileInSettings.js ~ 第 5 行 ~ EditProfileInSettings ~
componentDidMount ~ componentDidMount
知道这里发生了什么吗?
编辑 1: 我注意到这个错误只在我对组件内部的后端进行 API 调用时发生:
class PrivateRouteTestComponent extends Component {
componentDidMount() {
console.log("PrivateRouteTestComponent.componentDidMount is called!");
// If I comment this out, the problem will not occur.
// It only occurs with this line
// It does an API call to the backend to get user profile
this.props.getAuthenticatedUserProfile();
}
render() {
return (
<div>
<button
onClick={() => {
this.props.history.push("/videos-page");
}}
>
Home
</button>
<h6>Private route test component</h6>
</div>
);
}
}
EDIT 2: 我终于找到了为什么会出现这个错误。调用一个将某些东西分派到商店的函数将更新 PrivateRoute
,因此它会再次被调用:
class PrivateRouteTestComponent extends Component {
componentDidMount() {
console.log("PrivateRouteTestComponent.componentDidMount is called!");
// This doesn't cause the problem
testBackendCall();
// This causes the problem
// Because it dispatches an action to the store
// So PrivateRoute gets updated
this.props.testBackendCallThatDispatchesSomethingToTheStore();
}
render() {
return (
<div>
<button
onClick={() => {
this.props.history.push("/videos-page");
}}
>
Home
</button>
<h6>Private route test component</h6>
</div>
);
}
}
答案 0 :(得分:1)
您正在混合函数式组件和基于类的 React 组件,并期望 PrivateRoute
中的日志记录和 EditProfileInSettings
中的日志记录在渲染周期的同一时刻完成 - 但它是不是。
在 EditProfileInSettings
中,您登录安装阶段 (componentDidMount
),这在组件的渲染中发生一次(如果未卸载)。
在 PrivateRoute
中,您登录渲染阶段(相当于类 render
上的 Component
),每次 React 需要更新你的组件,因为它的 props 被改变了。
如果您希望两个日志记录相同,请将您的日志记录放在 useEffect()
上的 PrivateRoute
中,或者将您的日志记录放在 render()
上的 EditProfileInSettings
.
然后,要了解为什么您的功能组件会被渲染两次,请记录您的所有道具并找出两个周期之间的差异。
答案 1 :(得分:0)
这就是解决我的问题的方法。使用 React 钩子仅在挂载时执行功能组件中的代码。
const PrivateRoute = ({ component: Component, auth, ...rest }) => {
React.useEffect(() => {
// EXECUTE THE CODE ONLY ONCE WHEN COMPONENT IS MOUNTED
}, []);
return (
<Route
{...rest}
render={(props) =>
auth.isAuthenticated === true ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
}
/>
);
};