Javascript 在用户登录或未登录时实现条件导航栏的策略

Javascript 在用户登录或未登录时实现条件导航栏的策略,javascript,reactjs,redux,react-router,react-router-dom,Javascript,Reactjs,Redux,React Router,React Router Dom,背景:我正在创建一个非常基本的应用程序,它具有4种不同的功能:注册、登录、搜索和创建内容。从现在起,我可以登录到用户并防止未经授权的用户进入受保护的路由。这显示在我的Protected.js组件中。然而,我正在努力找到一种方法,在我的App.js导航栏中有条件地显示登录/注销按钮 后续问题:我是否应该将身份验证逻辑从我的Login.js路径中移到我的主App.js组件中并向下传递状态?这不是效率很低吗,因为每次我呈现一个新视图时,App.js都会使用我的后端API执行另一次获取,以验证用户是否有

背景:我正在创建一个非常基本的应用程序,它具有4种不同的功能:注册、登录、搜索和创建内容。从现在起,我可以登录到用户并防止未经授权的用户进入受保护的路由。这显示在我的
Protected.js
组件中。然而,我正在努力找到一种方法,在我的
App.js
导航栏中有条件地显示登录/注销按钮

后续问题:我是否应该将身份验证逻辑从我的
Login.js
路径中移到我的主
App.js
组件中并向下传递状态?这不是效率很低吗,因为每次我呈现一个新视图时,
App.js
都会使用我的后端API执行另一次获取,以验证用户是否有一个未过期的会话?这对一些人来说可能显得微不足道,但我很难思考如何有条件地高效地显示登录/注销按钮。我已经研究了上下文API,所以如果您觉得有必要,我愿意接受一些建议,但我对Redux并不熟悉(我一周前才开始做出反应)。我正在寻找经过深思熟虑的策略,因此如果您能尽最大努力提供完整和连贯的回答,我将不胜感激。我真的很感激

App.js

class App extends Component {
    render() {
        return(
            <Router>
                <div>
                    <Navbar bg="light" variant="light">
                        <Navbar.Brand href="#home">My Application</Navbar.Brand>
                        <Nav className="mr-auto">
                            <Link to="/signup" className="nav-link">Signup</Link>
                            <Link to="/login" className="nav-link">Login</Link>
                            <Link to="/feed" className="nav-link">Search</Link>
                            <Link to="/create-post" className="nav-link">Create</Link>
                        </Nav>
                        <Form inline>
                            <Button variant="outline-primary">Logout</Button>
                        </Form>
                    </Navbar>
                </div>
                <Switch>
                    <Route path = '/signup' component = {Signup} />
                    <Route path = '/login' component = {Login} />
                    <Route path = '/feed' component = {Feed} />
                    <ProtectedRoute path = '/create-post' component = {CreatePost} />
                </Switch>

            </Router>
        )
    }
}
 class Login extends Component {
    constructor(props) {
        super(props)

        this.state = {
            username: "",
            password: ""
        }

        this.handleChange = this.handleChange.bind(this)
        this.handleSubmitForm = this.handleSubmitForm.bind(this)
    }

    handleChange(event) {
        //console.log(event.target.name)
        this.setState({[event.target.name]: event.target.value})
    }

    handleSubmitForm() {
        const user = {
            username: this.state.username,
            password: this.state.password
        }

        const url = 'http://localhost:9000/api/login'

        fetch(url, {
            method: 'POST',
            credentials: 'include',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(user)
        })
        .then((response) => response.json())
        .then((data) => {
            if (data.status === 1) {
                this.props.history.push('/feed')
            }
            console.log(data)
        })
        .catch((error) => {
            console.log('Error', error)
        })
    }

    render() {
        return (
        <div>
            <Card className="card-login" style={{ width: '18rem' }}>
                <Card.Body>
                <Card.Title>Login</Card.Title>
                    <Form>
                        <Form.Group>
                            <Form.Control placeholder ="Username"
                                          name = "username"
                                          value = {this.state.username}
                                          onChange = {this.handleChange}/>
                        </Form.Group>
                        <Form.Group>
                            <Form.Control type ="password"
                                          placeholder="Password"
                                          name = "password"
                                          value = {this.state.password}
                                          onChange = {this.handleChange} />
                        </Form.Group>                   
                    <Button variant ="primary"
                            value="Submit"
                            onClick={this.handleSubmitForm}>Submit
                    </Button>
                    </Form>
                </Card.Body>
            </Card>         
        </div>)
    }
}
class ProtectedRoute extends Component {
    constructor(props) {
        super(props)

        this.state = {
            isAuthenticated: false,
            isLoading: true
        }
        this.isAuthenticated = this.isAuthenticated.bind(this)
    }

    componentDidMount() {
        this.isAuthenticated()
    }

    isAuthenticated() {
        const url = 'http://localhost:9000/api/auth'
        fetch(url, {
            method: 'GET',
            credentials: 'include',
            headers: {
                'Content-Type' : 'application/json'
            }
        })
        .then((response) => response.text())
        .then((data) => {
            if (data === 'true') {
                this.setState({
                    isAuthenticated: true,
                    isLoading: false
                })
            } else {
                this.setState({
                    isAuthenticated: false,
                    isLoading: false
                })
            }
        })
        .catch((err) => {
            console.log('Error', err)
        })
    }
    render() {
        const Component = this.props.component
        if (this.state.isLoading === true) {
            return (<div>Loading</div>)
        }
        return(
            <Route render={(props) => this.state.isAuthenticated && !this.state.isLoading ? (<Component {...this.props}/>) : (<Redirect to ='/login' />)} />
        )
            
    }
}

显然需要全局状态,您可以在
App
组件中使用React-Context、Redux甚至set-auth-state、pass方法来更改状态,即
setAuth
,作为
Login
组件的道具

class App extends Component {
  constructor(props) {
    super(props);
    this.setAuth = this.setAuth.bind(this);
    this.state = {
      isAuthenticated: false
    };
  }

  setAuth(value) {
    this.setState({
      isAuthenticated: value
    });
  }
}/>
我是否应该将身份验证逻辑移出Login.js路径并 进入我的主App.js组件并传递状态?那不是吗 效率很低,因为每次渲染新视图时 App.js正在使用我的后端api执行另一次获取,以验证 用户是否有未过期的会话

您是指
Protectedroute
组件中发生的逻辑吗?我会像你说的那样将其提取到
App
组件中,因为在一个场景中



当您想进入
“/update post”
部分时,它会检查用户是否多次经过身份验证。

谢谢您的详细回答。您给出的第一个响应是一个在子组件中修改应用程序状态的好例子。但是,关于您的第二个回答,我想确保我正确理解您:您是否建议我放弃
ProtectedRoute
,并将所有获取身份验证逻辑从
ProtectedRoute
移动到
应用程序中?如果是这样的话,我的
App
组件是否会在每次装载新组件时执行提取@Józef Podlecki如果您将请求放入
componentDidMount
,然后更改状态,则是,它仍将再次执行获取。但是
shouldComponentUpdate(nextProps)
起到了解救作用,在那里你可以做一个非常简单的谓词,它忽略
isAuthenticated
prop change或者一直返回
false
。这是公认的答案。感谢您提供反馈。@波德莱斯基
class App extends Component {
  constructor(props) {
    super(props);
    this.setAuth = this.setAuth.bind(this);
    this.state = {
      isAuthenticated: false
    };
  }

  setAuth(value) {
    this.setState({
      isAuthenticated: value
    });
  }