React 状态和用户在页面刷新或重定向主页时丢失,使用 React Context API

时间:2021-01-26 18:48:48

标签: reactjs redirect react-hooks react-context react-state-management

我使用有效的用户名和密码登录。
导航栏更改为欢迎用户和注销导航链接按钮。
单击导航左上角的主页或刷新页面会丢失用户对象,导航栏会读取登录和注册,即使用户未明确注销

如何使用 react hooks 修复状态管理,如示例中所示,而不使用诸如 localstorage、cookies、Auth0 等替代方法?

App.js

import './App.css';
import React, { useState, Component, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Route, Switch, Redirect } from "react-router-dom";
import { LinkContainer } from "react-router-bootstrap";
import Navbar from "react-bootstrap/Navbar";
import Nav from "react-bootstrap/Nav";
import axios from 'axios'
import Home from "./containers/Home";
import Login from "./containers/Login";
import Signup from "./containers/Signup";
import Rooms from './containers/Rooms';
import RoomShow from './containers/RoomShow';
import UserContext from './context/UserContext'

function App() {
  const [user, setUser] = useState(null);
  const [allChannels, setAllChannels] = useState([]);
  const [currentChannel, setCurrentChannel] = useState([]);
  
   const handleLogin = (data) => {
    setUser({
      user: data
    });
    fetch('/channels')
    .then(response => response.json())
    .then(result => {
      setAllChannels(result);
    })
  };

  const handleLogout = () => {
    setUser(null);   
  };

  const getRoomData = (id) => {
    fetch(`/rooms/${id}`)
    .then(response => response.json())
    .then(result => {
      setCurrentChannel(
        {
          room: result.data,
          users: result.data.attributes.users,
          messages: result.data.attributes.messages
        }
      )
    })
  };

  const subscribeToRoom = (event) => {
    const room_id = event.target.id
    user ? (this.postFirstMessage(room_id)) : (alert('You must be logged in to subscribe to a room.'))
  };

  const postFirstMessage = (roomId) => {
    window.history.pushState(null, null, `/rooms/${roomId}`)
    const message = {
      content: `${this.state.currentUser.attributes.username} has joined this room!`,
      user_id: this.state.user.id,
      channel_id: roomId
    }
    fetch("/messages", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            Accept: "application/json"
        },
        body: JSON.stringify({message: message})
    })
    .then(resp => resp.json())
    .then(result => {
    })
  };

    return (
      <UserContext.Provider value={user, setUser}>
        
      <div className="App container py-3">
      <Navbar collapseOnSelect bg="light" expand="md" className="mb-3">
        <Navbar.Brand href="/" className="font-weight-bold text-muted">
          Chat
        </Navbar.Brand>
        <Navbar.Toggle />
        <Navbar.Collapse className="justify-content-end">
          <Nav activeKey={window.location.pathname}>
            {user ? (
              <>
              <Navbar.Text> Welcome, USER </Navbar.Text>
              <Nav.Item><Nav.Link onClick={handleLogout}>Logout</Nav.Link>
              </Nav.Item>
              </>
            ) : (
              <>
                <LinkContainer to="/signup">
                  <Nav.Link>Signup</Nav.Link>
                </LinkContainer>
                <LinkContainer to="/login">
                  <Nav.Link>Login</Nav.Link>
                </LinkContainer>
              </>
            )}
          </Nav>
        </Navbar.Collapse>
      </Navbar>
      <Switch>
        <Route exact path="/">
          <Home />
        </Route>
        <Route exact path="/login"
        // props such as props.history
        // props.history.push used to redirection https://reactrouter.com/web/api/history
        render={ (props) => (<Login
                    {...props}
                    handleLogin={handleLogin} />) } />
        <Route exact path="/signup"
          render={ (props) => (<Signup
                    {...props} 
                    handleLogin={handleLogin} />) } />
        <Route exact path='/rooms' 
          render={ (props) => (<Rooms />) } />
        <Route exact path='/rooms/:id' 
          render={ (props) => {
            return user ? (<RoomShow {...props}
            cableApp={this.props.cableApp}
            getRoomData={this.getRoomData}
            updateApp={this.updateAppStateRoom}
            roomData={this.state.currentRoom}
            currentUser={this.state.user.data}
          />
          ) : (
            <Redirect to='/rooms' />
          )
          }} />
      </Switch>
    </div>
    </UserContext.Provider>
  );

}

export default App;

容器/Login.js

import "./Login.css";
import axios from 'axios'
import React, { useState } from "react";
import { Link } from 'react-router-dom'
import Form from "react-bootstrap/Form";
import Button from "react-bootstrap/Button";
import  UserContext  from '../context/UserContext'

function Login(props){
  const [login, setLogin] = useState({username: null, password: null, errors: null})

  const handleChange = (event) => {
      const {name, value} = event.target
      setLogin({
        ...login,
        [name]: value
      })
    };
  
  const handleSubmit = (event) => {
    event.preventDefault()
    const {username, password} = login
    let user = {
      username: username,
      password: password
  }
  axios.post('/login', {user}, {withCredentials: true})
    .then(response => {
      if (response.data.logged_in) {
        props.handleLogin(response.data)
        redirect();
      } else {
        handleErrors();
        console.log('response errors:', response.data.errors)
        setLogin({
          ...login,
          errors: response.data.errors
        })
      }
    })
    .catch(error => {
      handleErrors();
      console.log('api errors:', error)
    })
  };


  const redirect = () => {
    props.history.push('/')
  }

  const handleErrors = () => {
  };

  return (
    <div className="Login">
    <Form onSubmit={handleSubmit}>
      <Form.Group size="lg" controlId="username">
      <Form.Label>Username</Form.Label>
      <Form.Control
          autoFocus
          type="text"
          name="username"
          onChange={handleChange}
      />
      </Form.Group>
      <Form.Group size="lg" controlId="password">
      <Form.Label>Password</Form.Label>
      <Form.Control
          type="password"
          name="password"
          onChange={handleChange}
      />
      </Form.Group>
      <Button block size="lg" type="submit">
      Login
      </Button>
      <div>
          or <Link to='/signup'>sign up</Link>
      </div>
    </Form>
    </div>
  );
}

export default Login;

容器/Home.js

import React from "react";
import "./Home.css";

export default function Home() {
  return (
    <div className="Home">
      <div className="lander">
        <h1>Chat</h1>
        <p className="text-muted">A simple chat application</p>
      </div>
    </div>
  );
}

上下文/UserContext.js

import React from 'react'

const UserContext = React.createContext(null)

export default UserContext

注意:
我之前在多个孩子上使用过 <UserContext.Consumer/> 但由于错误而省略了

TypeError: render is not a function

0 个答案:

没有答案