Стратегии реализации условного Navbar, если пользователь вошел в систему или нет - PullRequest
1 голос
/ 24 апреля 2020

Фон : я создаю очень простое c приложение с 4 различными возможностями: регистрация, вход в систему, поиск и создание контента. На данный момент я могу входить в систему пользователей и предотвращать несанкционированный доступ пользователей к защищенным маршрутам. Это показано ниже в моем Protected.js компоненте. Однако я изо всех сил пытаюсь найти способ также условно отображать кнопку входа / выхода из системы на панели навигации, расположенной в моем App.js.

Контрольные вопросы : Должен ли я переместить логи аутентификации c с моего маршрута Login.js в мой основной компонент App.js и передать состояние вниз? Разве это не было бы очень неэффективно, потому что каждый раз, когда я рендерил новое представление, App.js выполняет другую выборку с моим API бэкэнда, чтобы проверить, есть ли у пользователя сеанс с истекшим сроком действия? Для некоторых это может показаться тривиальным, но мне трудно обдумать, как эффективно отобразить кнопку входа / выхода из системы. Я изучил Context API, поэтому я буду готов дать несколько советов по этому пути, если вы сочтете это необходимым, но я не знаком с Redux ( Я только начал React неделю a go). Я ищу хорошо продуманные стратегии, поэтому я был бы очень признателен, если бы вы приложили все усилия, чтобы предоставить полные и последовательные ответы. Я очень ценю это.

Приложение. 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>
        )
    }
}

Вход. js

 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>)
    }
}

Protectedroute . js

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' />)} />
        )

    }
}

API. js (Express Backend)

router.post('/login', function(req,res,next) {
    const query1 = "SELECT * FROM users WHERE username = TRIM(?) AND pass = TRIM(?)"
    database.query(query1, [req.body.username, req.body.password])
    .then((result) => {
        if (result.length) {
            if (req.session.username) {
                res.json({'message': 'You are already logged in', 'status': 0})
            } else {
                req.session.username = req.body.username
                res.json({'message': 'You have successfully logged in', 'status': 1})
            }
        } else {
            if (req.session.username) {
                res.json({'message': 'You are already logged in', 'status': 0})
            } else {
                res.json({'message': 'Incorrect Credentials', 'status': 0})
            }
        }
    }).catch((err) => res.send(err))
})



router.get('/auth', (req, res, next) => {
    if (req.session.username) {
        res.send(true)
    } else {
        res.send(false)
    }
})

1 Ответ

1 голос
/ 24 апреля 2020

Что ж, существует явная потребность в глобальном состоянии, и вы можете использовать React Context, Redux или даже установить состояние авторизации в компоненте App, передавать методы, которые изменяют состояние ie. setAuth, as props для 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
    });
  }
<Route path='/login' component={() => <Login setAuth={this.setAuth} />} />

Должен ли я переместить логи аутентификации c из моего логина. js по маршруту в мое основное приложение js компонента и передать состояние вниз? Разве это не было бы очень неэффективно, потому что каждый раз, когда я рендерил новое представление, приложение. js выполняет другую выборку с моим backind api, чтобы проверить, есть ли у пользователя сеанс с истекшим сроком действия?

Вы имели в виду логи c, которые происходят в Protectedroute компоненте? Я бы извлек это в App компонент, как вы сказали, потому что в сценарии

<ProtectedRoute path = '/create-post' component = {CreatePost} />
<ProtectedRoute path = '/post-list' component = {PostList} />
<ProtectedRoute path = '/update-post' component = {UpdatePost} />

Он будет проверять, прошел ли пользователь аутентификацию несколько раз, когда вы хотите попасть в секцию '/update-post'.

...