草庐IT

关于 reactjs:React 路由器私有路由未从状态获取道具(例如身份验证状态)

codeneng 2023-03-28 原文

React router private route not getting props from state (e.g. authentication state)

我正在尝试实现一个私有路由组件来重定向未通过身份验证的用户。问题是当我渲染像 <PrivateRoute authenticated={this.state.isAuthenticated} path='/private' component={Panel} currentUser={this.state.currentUser} 这样的组件时,私有路由会将经过身份验证的用户重定向到登录页面,而不是转到面板。

App.js 中,我渲染了所有的路由,包括 <PrivateRoute/>,我在 ComponentDidMount() 中设置了 currentUserisAuthenticated 状态变量,但我无法将它们传递给 PrivateRoute

App.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//imports...
class App extends Component {

    state = {
        currentUser: null,
        isAuthenticated: false,
        isLoading: false
    }

    loadCurrentUser = () => {
    this.setState({
      isLoading: true
        });
        // imported method
        getCurrentUser()
            .then(response => {
                this.setState({
                    currentUser: response,
                    isAuthenticated: true,
                    isLoading: false
                });
            })
            .catch(error => {
                console.log(error)
                this.setState({
                    isLoading: false
                });  
            });
  }

  componentDidMount() {
        this.loadCurrentUser();
  }

  handleLogin = () => {
        this.loadCurrentUser();
        this.props.history.push("/");
    }

    render () {
        return (
            <React.Fragment>
                <Navigation
                    currentUser={this.state.currentUser}
                    isAuthenticated={this.state.isAuthenticated}
                    handleLogout={this.handleLogout} />
                <Switch>
                    <PrivateRoute
                        authenticated={this.state.isAuthenticated}
                        exact
                        path='/postulante'
                        component={Panel}
                        currentUser={this.state.currentUser} />
                    <Route
                        exact
                        path='/'
                        render={
                            (props) => <Landing {...props} />
                        } />

                    <Route
                        path="/login"
                        exact
                        render={
                            (props) =>  <Login onLogin={this.handleLogin} {...props} />
                        } />
                </Switch>
            </React.Fragment>
        );
    }
}

export default withRouter(App);

请注意,<Navigation /> 组件确实获得了正确的状态变量。

PrivateRoute.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//imports...
const PrivateRoute = ({ component: Component, authenticated, ...rest }) => (
    <Route
      {...rest}
      render={props =>
        authenticated ? (
          <Component {...rest} {...props} />
        ) : (
          <Redirect
            to={{
              pathname: '/login',
              state: { from: props.location }
            }}
          />
        )
      }
    />
);
export default PrivateRoute

  • 你好 !刚刚给你写了一个解决方案和一个沙箱供你参考。如果您有任何问题,请告诉我:)


问题与 PrivateRoute 组件在第一次渲染时没有任何来自主 App 组件的更新道具有关。

如果您直接导航到 PrivateRoute 路径而不先进入任何其他路由,您将被重定向回 /login。您的 PrivateRoute 尝试在父 App\\ 的 componentDidMount() 逻辑完成之前呈现。所以 isAuthenticated 被传递为假。

如果您从 HomeLogin 开始,然后使用 Link 转到 PrivateRoute,则会发生相反的情况。

最终,这就是为什么人们使用像 redux 这样的状态管理工具来让经过身份验证的状态在全球范围内共享,而不是通过父组件传递。

虽然有一个解决方法!

参考沙箱:https://codesandbox.io/s/intelligent-dan-uskcy

  • 我们可以通过使用额外的状态值来解决这个问题
    App 组件是否曾被初始化。我们称之为
    wasInitialized
  • PrivateRoute 将接收它作为称为 wasInitialized 的道具,如果
    我们直接进入它的组件路径,在 App 有机会完成它的 componentDidMount() 逻辑之前,wasInitialized 将为 false。
  • 如果 wasInitialized 是假的,我们不会重定向到 /login,
    相反,我们将只显示一个空字符串,给父 App\\'s
    componentDidMount() 时间来执行和更新
    isAuthenticated 值。
  • 现在让我们看一下这一行:

    <Route {...rest} render={props => auth === true ? <Component
    {...props} /> : !wasInitialized ? "" : <Redirect to="/login" />
    }

    在下一次重新渲染中,isAuthenticated 将是 true 或
    错误的。如果用户是Authenticated,我们渲染预期的组件。如果用户未通过身份验证,我们进行下一个检查。现在 wasInitialized 的值为 true,因此 check 的计算结果为 false。因此,由于两个检查都没有通过,我们重定向到 /login.

  • 应用程序.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    class App extends Component {

    state = {
        currentUser: null,
        isAuthenticated: false,
        isLoading: false,
        wasInitialized: false
    }

    loadCurrentUser = () => {
    this.setState({
      isLoading: true
        });
        // imported method
        getCurrentUser()
            .then(response => {
                this.setState({
                    currentUser: response,
                    isAuthenticated: true,
                    wasInitialized: true,
                    isLoading: false
                });
            })
            .catch(error => {
                console.log(error)
                this.setState({
                    isLoading: false,
                    wasInitialized: true
                });  
            });
      }

      componentDidMount() {
            this.loadCurrentUser();
      }

      handleLogin = () => {
            this.loadCurrentUser();
            this.props.history.push("/");
        }
    render () {
        return (
            <React.Fragment>
                <Navigation
                    currentUser={this.state.currentUser}
                    isAuthenticated={this.state.isAuthenticated}
                    handleLogout={this.handleLogout} />
                <Switch>
                    <PrivateRoute
                        authenticated={this.state.isAuthenticated}
                        path='/postulante'
                        component={Panel}
                        wasInitialized={this.state.wasInitialized}
                        currentUser={this.state.currentUser} />
                    <Route
                        exact
                        path='/'
                        render={
                            (props) => <Landing {...props} />
                        } />

                    <Route
                        path="/login"
                        exact
                        render={
                            (props) =>  <Login onLogin={this.handleLogin} {...props} />
                        } />
                </Switch>
            </React.Fragment>
        );
    }
    }

    export default withRouter(App);

    私人的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    import React from"react";
    import { Route, Redirect } from"react-router-dom";

    const PrivateRoute = ({
      component: Component,
      auth,
      wasInitialized,
      ...rest
    }) => {
      return (
        <Route
          {...rest}
          render={props =>
            auth === true ? (
              <Component {...props} />
            ) : !wasInitialized ? (
             ""
            ) : (
              <Redirect to="/login" />
            )
          }
        />
      );
    };

    export default PrivateRoute;

    • 是的,这就是我的想法,但我不知道如何解决。谢谢!顺便说一句,在解决方案中,App.js 应该已经在状态下被初始化了。

    有关关于 reactjs:React 路由器私有路由未从状态获取道具(例如身份验证状态)的更多相关文章

    1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    2. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

      我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

    3. ruby-on-rails - Rails 3 中的多个路由文件 - 2

      Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

    4. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

      我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

    5. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

      我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

    6. ruby-on-rails - 跳过状态机方法的所有验证 - 2

      当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

    7. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

      我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

    8. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

      对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

    9. ruby - Net::HTTP 获取源代码和状态 - 2

      我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

    10. ruby-on-rails - Rails 3,嵌套资源,没有路由匹配 [PUT] - 2

      我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle

    随机推荐