Я использую 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
Я довольно новый разработчик, пожалуйста, дайте мне знать, если есть дополнительная информация, необходимая для диагностики проблемы. любой совет будет полезен, спасибо!!
Проблема именно в этом history.push
.
Сначала вы должны импортировать: import { useHistory } from 'react-router-dom';
в свой файл, затем объявить, что history
нравится: const history = useHistory()
и эта ошибка больше не будет отображаться.
Я использовал const
, потому что в основном использую функциональные компоненты :D.
Вы не можете использовать хуки в своем компоненте class
.
а, хорошо, мне просто нужно сделать это функциональным компонентом, как я полагаю? Я попробую, когда вернусь к этому.
Вы можете попробовать ответ, который я предоставил, чтобы увидеть, работает ли он с вашей текущей настройкой.
Проблема в том, что this.props.history
есть undefined
.
Попробуйте обернуть компонент входа в систему следующим образом.
Сначала import { withRouter } from "react-router";
поверх вашего файла Login.js.
И экспортируйте вот так export default withRouter(Login)
.
спасибо за быстрый ответ, я импортировал 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:[] }
Он говорит мне, что это недопустимый вызов ловушки, мне нужно поместить это куда-то конкретно?