JWT Auth выдает ошибку при попытке войти в систему пользователя

Я использую JWT с бэкэндом Rails/интерфейсом React. Я пытаюсь перенаправить моего пользователя, когда он входит в свою учетную запись, на / домашнюю страницу сайта. Ошибка, которую я получаю,

TypeError: Cannot read property 'push' of undefined
Login.<anonymous>
src/components/Login.js:20
 17 |   if (res.user){
 18 |     localStorage.token = res.token
 19 |     this.setState({user:{id:res.user.id, username:res.user.username, token:res.token}, home:res.user.home}, () => {
> 20 |     this.props.history.push('/home')
    | ^  21 |   })
 22 | } else {
 23 |     alert(res.error)

Я внес изменения в домашний компонент, но с тех пор вернулся к тому, что было, но все еще имеет проблемы ....

мои контроллеры...

class ApplicationController < ActionController::API
  def encode_token(payload)
      JWT.encode(payload, "coffee")
  end 

def auth_header
  # { Authorization: 'Bearer <token>' }
  request.headers['Authorization']
end

def decoded_token
  if auth_header
    token = auth_header.split(' ')[1]
    # header: { 'Authorization': 'Bearer <token>' }
    begin
      JWT.decode(token,'coffee', true, algorithm: 'HS256')
    rescue JWT::DecodeError
      nil
    end
  end
end

def current_user
  if decoded_token
    user_id = decoded_token[0]['user_id']
    @user = User.find_by(id: user_id)
  end
end

def logged_in?
  !!current_user
end

def authorized
  render json: { message: 'Please log in' }, status: :unauthorized unless logged_in?
end
end
----
class UsersController < ApplicationController
    before_action :authorized, only:[:persist]

    def create
        @user = User.create(user_params)
        if @user.valid?
            token = encode_token({user_id: @user.id})   
            render json: @user
        else 
            render json: {error:'failed to create a user'}
        end
    end 

    def login
        @user = User.find_by(username:params[:username])
        if @user && @user.authenticate(params[:password])
            token = encode_token({user_id: @user.id})
            render json: {user:UserSerializer.new(@user), token:token}
        else
            render json: {error:"wrong user or password"}
        end 
        
    end 
    
    def index 
        @user = User.all
        render json: @user
    end
    def persist
        token = encode_token({user_id: @user.id})
        render json: {user:UserSerializer.new(@user), token:token} 
    end 

    private 
    def user_params
        params.permit(:username, :password)
    end 
end

мой user_serializer...

class UserSerializer < ActiveModel::Serializer
    attributes :id, :username
    has_many :favorites
    has_many :favorite_coffee_shops, through: :favorites, source: :coffee_shop
    has_many :reviews
    has_many :coffee_shops, through: :reviews
  end

мой компонент входа...

import React from "react";
import SignUp from "./SignUp"
import { useHistory } from 'react-router-dom';
import { withRouter } from "react-router";
export default withRouter(Login)

const history = useHistory();

const Login = {
  username: '',
  password: ''
}

   
function handleAuthResponse(res){
     if (res.user){
       localStorage.token = res.token
       this.setState({user:{id:res.user.id, username:res.user.username, token:res.token}, home:res.user.home}, () => {
       this.props.history.push('/home')
     })
   } else {
       alert(res.error)
     }
   }

function handleLogin(e, userInfo) {
    e.preventDefault()
    console.info(e)
 
    fetch('http://localhost:3000/login',{
     method:"POST",
     headers:{
       'Content-Type':'application/json'
     },
     body:JSON.stringify(userInfo)
   })
   .then(res => res.json())
   .then(json => {
     console.info(json)
     if (!json.error){
       handleAuthResponse(json)
     }else {
       alert(json.error)
     }
   })
   .catch(err => console.info(err))
  }
 
  
function handleChangeEvent(e) {
  let {name, value} = e.target
    this.setState({
      [name]: value
    })
  }

return (
<div className = "login">Welcome Back!
  <form onSubmit = {(e) => this.handleLogin(e, this.state)}>
<div>
    <label>UserName</label>
    <br></br>
    <input type = "text" name = "username" value = {this.state.username} onChange = {handleChangeEvent}/>
    </div>
    <div>
    <label>Password</label>
    <br></br>
    <input type = "password" name = "password" value = {this.state.password} onChange = {handleChangeEvent}/>
    </div>
    <input type = "submit" value = "Submit" className = "sl-btn" />
  </form>
<div></div>
  <SignUp />
  </div>
  )

и мой домашний компонент я пытаюсь подтолкнуть пользователя к входу в систему

import React from 'react'
import MapContainer  from '../containers/MapContainer'
import NavBar from './NavBar'
import FavoritesContainer  from './FavoritesContainer'

class Home extends React.Component {

    state = {
        reviews: [],
        favorites: [],
    }

    componentDidMount(){
    fetch('http://localhost:3000/reviews')
    .then(res => res.json())
    .then(reviews => this.setState({ reviews }))
    }
              
    addReview = (review) => {
        fetch('http://localhost:3000/reviews',{
            method: "POST",
            headers: {
                "Content-Type" : "application/json",
                Accept: "application/json",
                Authorization: `bearer ${localStorage.token}`
            },
            body: JSON.stringify({ review: review }
            ),
        })
        .then(res => res.json())
        .then(( json => {
            this.setState(prevState => ({
                reviews: [...prevState.reviews, json ]
               }))
        }))
    }
  
    render() {
        return (
               <div className = "home">
                   <NavBar />
                   <MapContainer />
                   <FavoritesContainer />
           </div>
        )
}
}

export default Home

Я довольно новый разработчик, пожалуйста, дайте мне знать, если есть дополнительная информация, необходимая для диагностики проблемы. любой совет будет полезен, спасибо!!

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
630
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Проблема именно в этом history.push. Сначала вы должны импортировать: import { useHistory } from 'react-router-dom'; в свой файл, затем объявить, что history нравится: const history = useHistory() и эта ошибка больше не будет отображаться.

Я использовал const, потому что в основном использую функциональные компоненты :D.

спасибо за быстрый ответ, я импортировал useHistory и теперь пытаюсь вставить ``` history = useHistory();```, но это дает мне ошибки. import React from 'react'; import { useHistory } from 'react-router-dom'; import SignUp from './SignUp'; class Login extends React.Component{ history = useHistory(); state = { user:{ id:0, username:"", token:"" }, home:[] } Он говорит мне, что это недопустимый вызов ловушки, мне нужно поместить это куда-то конкретно?

Gabe571 12.12.2020 20:29

Вы не можете использовать хуки в своем компоненте class.

Nemanja Lazarevic 12.12.2020 20:38

а, хорошо, мне просто нужно сделать это функциональным компонентом, как я полагаю? Я попробую, когда вернусь к этому.

Gabe571 12.12.2020 20:43

Вы можете попробовать ответ, который я предоставил, чтобы увидеть, работает ли он с вашей текущей настройкой.

Nemanja Lazarevic 12.12.2020 21:06

Проблема в том, что this.props.history есть undefined. Попробуйте обернуть компонент входа в систему следующим образом.

Сначала import { withRouter } from "react-router"; поверх вашего файла Login.js.

И экспортируйте вот так export default withRouter(Login).

Другие вопросы по теме