将基于Reaction路由器v4类的代码重写为基于v6功能的代码

我正在尝试使用Reaction和Spring Boot实现Oauh登录,我找到了一个可以遵循的教程。

我遇到的问题是它使用的是Reaction Router v4,我希望将其更新为使用Reaction 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} 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,我已将其更新为使用功能组件并响应路由器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 y.place、location.pathname等)和功能组件(而不是基于类)的Reaction路由器功能的等价物。

  2. 另外,如果有人能解释一下这句话,请 <LoginForm {...this.props} />


解决方案

第一季度

我很难理解Reaction路由器的等价物 V6的功能(location.state.error,history.place, location.pathname等)和功能组件,而不是类 基于。

react-router-domV6中不再有路线道具,即没有historylocationmatchRoute组件也不再具有引用Reaction组件或返回JSX的函数的componentrender道具,取而代之的是接受JSX文字的element道具,即ReactElement。

如果我理解正确,您正在询问如何将RRDv6与类组件LoginSignup一起使用。

您有几个选项:

  1. LoginSignup也转换为Reaction函数组件,并使用新的Reaction挂钩。

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

    • useNavigate-history对象已替换为navigate函数。

      const navigate = useNavigate();
      
      ...
      
      navigate("....", { state: {}, replace: true });
      
    • useLocation

      const { pathname, state } = useLocation();
      
  2. 创建可使用挂钩并将其作为道具传递的自定义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...
        />
      );
    };
    

    修饰LoginSignup导出:

    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

相关文章