将基于 React 路由器 v4 类的代码重写为基于 v6 功能的代码
Posted
技术标签:
【中文标题】将基于 React 路由器 v4 类的代码重写为基于 v6 功能的代码【英文标题】:Rewriting React router v4 class based code to v6 functional based 【发布时间】:2022-01-20 08:49:05 【问题描述】:我正在尝试使用 react 和 spring boot 实现 oauh 登录,我找到了一个可以学习的教程。
我遇到的问题是它使用 React Router v4,我想更新它以使用 React Router v6 并改用功能组件。
Login.js
import React, Component from 'react';
import './Login.css';
import GOOGLE_AUTH_URL, FACEBOOK_AUTH_URL, GITHUB_AUTH_URL, ACCESS_TOKEN from '../../constants';
import login from '../../util/APIUtils';
import Link, Redirect from 'react-router-dom'
import fbLogo from '../../img/fb-logo.png';
import googleLogo from '../../img/google-logo.png';
import githubLogo from '../../img/github-logo.png';
import Alert from 'react-s-alert';
class Login extends Component
componentDidMount()
// If the OAuth2 login encounters an error, the user is redirected to the /login page with an error.
// Here we display the error and then remove the error query parameter from the location.
if(this.props.location.state && this.props.location.state.error)
setTimeout(() =>
Alert.error(this.props.location.state.error,
timeout: 5000
);
this.props.history.replace(
pathname: this.props.location.pathname,
state:
);
, 100);
render()
if(this.props.authenticated)
return <Redirect
to=
pathname: "/",
state: from: this.props.location
/>;
return (
<div className="login-container">
<div className="login-content">
<h1 className="login-title">Login to SpringSocial</h1>
<SocialLogin />
<div className="or-separator">
<span className="or-text">OR</span>
</div>
<LoginForm ...this.props />
<span className="signup-link">New user? <Link to="/signup">Sign up!</Link></span>
</div>
</div>
);
class SocialLogin extends Component
render()
return (
<div className="social-login">
<a className="btn btn-block social-btn google" href=GOOGLE_AUTH_URL>
<img src=googleLogo /> Log in with Google</a>
<a className="btn btn-block social-btn facebook" href=FACEBOOK_AUTH_URL>
<img src=fbLogo /> Log in with Facebook</a>
<a className="btn btn-block social-btn github" href=GITHUB_AUTH_URL>
<img src=githubLogo /> Log in with Github</a>
</div>
);
App.js
这是带有路由的 App.js,我已将其更新为使用功能组件和 React Router v6。//imports left out
function App()
const [globalUserState, setGlobalUserState] = useState(
authenticated: false,
currentUser: null,
loading: true
);
useEffect(() =>
loadCurrentlyLoggedInUser();
)
const loadCurrentlyLoggedInUser = () =>
getCurrentUser()
.then(res =>
setGlobalUserState(
currentUser: res,
authenticated: true,
loading: false
);
).catch(err =>
setGlobalUserState(
loading: false
)
)
const handleLogout = () =>
localStorage.removeItem(ACCESS_TOKEN);
setGlobalUserState(
authenticated: false,
currentUser: null
);
Alert.success("You're safely logged out!");
return (
<Router>
<div className="app">
<div className="app-header">
<AppHeader />
</div>
<Routes>
<Route path="/" element=<Home /> />
<Route path="/profile" element=<SecuredRoute> <Profile /> </SecuredRoute> />
<Route path="/login" element=(props) => <Login authenticated=globalUserState.authenticated ...props /> />
<Route path="/signup" element=(props) => <Signup authenticated=globalUserState.authenticated ...props /> />
<Route path="/oauth2/redirect" element=<OAuth2RedirectHandler /> />
<Route path="*" element=<Notfound /> />
</Routes>
<Alert stack=limit: 3
timeout = 3000
position='top-right' effect='slide' offset=65
/>
</div>
</Router>
);
export default App;
我想弄清楚什么
我正在努力理解与 v6(location.state.error、history.replace、location.pathname 等)和功能组件而不是基于类的反应路由器功能的等价物。
另外,如果有人可以解释这一行,请
<LoginForm ...this.props />
【问题讨论】:
【参考方案1】:第一季度
我很难理解 react 路由器的等价物 v6 的功能(location.state.error,history.replace, location.pathname 等)和功能组件而不是类 基于。
在react-router-dom
v6 中不再有路由道具,即没有history
、location
,也没有match
。 Route
组件也不再具有引用 React 组件或返回 JSX 的函数的 component
或 render
属性,取而代之的是采用 JSX 文字的 element
属性,即 ReactElement .
如果我正确理解您的问题,您是在问如何使用 RRDv6 with 类组件 Login
和 Signup
。
你有几个选择:
也将 Login
和 Signup
转换为 React 函数组件并使用新的 React 钩子。
我不会介绍转换,但要使用的钩子是:
useNavigate
- history
对象被 navigate
函数替换。
const navigate = useNavigate();
...
navigate("....", state: , replace: true );
useLocation
const pathname, state = useLocation();
创建一个自定义的withRouter
组件,该组件可以使用钩子并将它们作为道具传递。
const withRouter = WrappedComponent => props =>
const navigate = useNavigate();
const location = useLocation();
// etc... other react-router-dom v6 hooks
return (
<WrappedComponent
...props
navigate=navigate
location=location
// etc...
/>
);
;
装饰Login
和Signup
出口:
export default withRouter(Login);
从this.props.history.push
交换到this.props.navigate
:
componentDidMount()
// If the OAuth2 login encounters an error, the user is redirected to the /login page with an error.
// Here we display the error and then remove the error query parameter from the location.
if (this.props.location.state && this.props.location.state.error)
setTimeout(() =>
const pathname, state = this.props.location;
Alert.error(state.error, timeout: 5000 );
this.props.navigate(
pathname,
state: , replace: true
);
, 100);
剩下的就是修复 App
中的路由,以便它们正确呈现 JSX。
<Router>
<div className="app">
<div className="app-header">
<AppHeader />
</div>
<Routes>
<Route path="/" element=<Home /> />
<Route
path="/profile"
element=(
<SecuredRoute>
<Profile />
</SecuredRoute>
)
/>
<Route
path="/login"
element=<Login authenticated=globalUserState.authenticated />
/>
<Route
path="/signup"
element=<Signup authenticated=globalUserState.authenticated />
/>
<Route path="/oauth2/redirect" element=<OAuth2RedirectHandler /> />
<Route path="*" element=<Notfound /> />
</Routes>
<Alert stack=limit: 3
timeout = 3000
position='top-right' effect='slide' offset=65
/>
</div>
</Router>
第二季度
另外,如果有人可以解释这一行,请
<LoginForm ...this.props />
这只是简单地将所有传递给父组件的道具复制/传递给LoginForm
组件。
<LoginForm ...this.props />
Login
传递了一个 authenticated
道具以及注入的任何新“路由道具”,以及您可能正在使用的任何其他 HOC 注入的任何其他道具,以上将它们全部传递给 LoginForm
.
【讨论】:
非常感谢您的明确解释。感谢您的帮助:D以上是关于将基于 React 路由器 v4 类的代码重写为基于 v6 功能的代码的主要内容,如果未能解决你的问题,请参考以下文章
在 react-router v4 中将自定义道具传递给路由器组件
React Hooks with React Router v4 - 我如何重定向到另一个路由?
使用 React 路由器 v4 在 react-boilerplate 中加载异步减速器和 sagas