我正在尝试使用 react 和 spring boot 实现 oauh 登录,并且找到了一个可以遵循的教程。
我遇到的问题是它使用的是 React Router v4,我想将其更新为使用 React Router v6 并使用功能组件。
登录.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} alt="Google" /> Log in with Google</a> <a className="btn btn-block social-btn facebook" href={FACEBOOK_AUTH_URL}> <img src={fbLogo} alt="Facebook" /> Log in with Facebook</a> <a className="btn btn-block social-btn github" href={GITHUB_AUTH_URL}> <img src={githubLogo} alt="Github" /> Log in with Github</a> </div> ); } }
App.js
//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;
我希望澄清的是
<LoginForm {...this.props} />
我正在努力理解与 v6(location.state.error、history.replace、location.pathname 等)和功能组件(而不是基于类)等效的反应路由器功能。
在react-router-domv6 中,不再有路由 props,即没有history、location和 没有match。Route组件也不再具有component或render引用 React 组件或返回 JSX 的函数的 props,而是被element采用 JSX 文字的 prop 所取代,即 ReactElement。
react-router-dom
history
location
match
Route
component
render
element
如果我正确理解了您的问题,您是在问如何将 RRDv6与类组件一起使用Login。Signup
Login
Signup
您有几个选择:
我不会介绍转换,但是要使用的钩子是:
useNavigate-history对象已被navigate函数取代。
useNavigate
navigate
```js const navigate = useNavigate();
…
navigate(“....”, { state: {}, replace: true }); ```
useLocation
js const { pathname, state } = useLocation();
创建一个withRouter可以使用钩子并将它们作为道具传递下去的自定义组件。
withRouter
```js 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出口:
js export default withRouter(Login);
交换自this.props.history.push至this.props.navigate:
this.props.history.push
this.props.navigate
js 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。
App
<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} />
这只是将传递给父组件的所有 props 复制/传递给组件LoginForm。
LoginForm
Login传递了一个authenticatedprop 以及任何新的“路线 props” 被注入,以及任何其他你可能正在使用的 HOC 注入的 props,并且上面将它们全部传递给LoginForm。
authenticated