小能豆

将基于 React router v4 类的代码重写为基于 v6 函数的代码

javascript

我正在尝试使用 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

  • 这是带有路由的 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;

我希望澄清的是

  1. 我正在努力理解与 v6(location.state.error、history.replace、location.pathname 等)和功能组件(而不是基于类)等效的反应路由器功能。
  2. 另外,如果有人可以解释这一行,请 <LoginForm {...this.props} />

阅读 43

收藏
2024-06-16

共1个答案

小能豆

问题 1

我正在努力理解与 v6(location.state.error、history.replace、location.pathname 等)和功能组件(而不是基于类)等效的反应路由器功能。

react-router-domv6 中,不再有路由 props,即没有historylocation和 没有matchRoute组件也不再具有componentrender引用 React 组件或返回 JSX 的函数的 props,而是被element采用 JSX 文字的 prop 所取代,即 ReactElement。

如果我正确理解了您的问题,您是在问如何将 RRDv6与组件一起使用LoginSignup

您有几个选择:

  1. Login和转换Signup为 React 函数组件并使用新的 React hooks。

我不会介绍转换,但是要使用的钩子是:

  • useNavigate-history对象已被navigate函数取代。

    ```js
    const navigate = useNavigate();

    navigate(“....”, { state: {}, replace: true });
    ```

  • useLocation

    js const { pathname, state } = useLocation();

  • 创建一个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...
   />
 );

};
```

装饰LoginSignup出口:

js export default withRouter(Login);

交换自this.props.history.pushthis.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。

<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 {...this.props} />

Login传递了一个authenticatedprop 以及任何新的“路线 props” 被注入,以及任何其他你可能正在使用的 HOC 注入的 props,并且上面将它们全部传递给LoginForm

2024-06-16