修复React Native中TypeError: null is not an object错误求助
我遇到了如下错误:LOG [TypeError: null is not an object (evaluating 'JSON.parse(value).token')],已检查代码拼写且后端服务正常运行,希望有人帮忙排查代码问题。相关代码如下:
Profile组件代码
import { StyleSheet, View, StatusBar, Text, Image, ActivityIndicator } from 'react-native'; import React, { useEffect, useState } from 'react'; import ButtomNavbar from '../../Components/ButtomNavbar'; import TopNavbar from '../../Components/TopNavbar'; import { formHead } from '../../CommonCss/FormCss'; import { ScrollView } from 'react-native-gesture-handler'; import defaultprofileimg from '../../../assets/profileimg.jpg'; import AsyncStorage from '@react-native-async-storage/async-storage'; const Profile = ({ navigation }) => { const [userdata, setUserdata] = useState(null) useEffect(() => { AsyncStorage.getItem('user') .then(async (value) => { fetch('http://10.0.2.2:3000/userdata', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization' : 'Bearer' + JSON.parse(value).token }, body: JSON.stringify({ email: JSON.parse(value).user.email }) }) .then(res => res.json()).then(data => { if (data.message == 'User Data Fetched Susscessfully') { setUserdata(data.user) } else { alert('Something went wrong') navigation.navigate('login') } }) .catch(err => { alert(err) console.log(err) }) }) .catch(err => { alert(err) console.log(err) }) }, []) console.log(userdata) return ( <View style={styles.container}> <StatusBar /> <ButtomNavbar navigation={navigation} page={'profile'} /> <TopNavbar navigation={navigation} page={'profile'} /> { userdata? <ScrollView> <View style={styles.section1}> { userdata.profileImg.length>0 ? <Image style={styles.profileimg} source={{ uri: userdata.profileImg}} /> : <Image style={styles.profileimg} source={defaultprofileimg} /> } <Text style={styles.usernameText}>@{userdata.username}</Text> <View style={styles.Postrow}> <View style={styles.Postrow1}> <Text style={styles.followerTxt}>UpVotes</Text> <Text style={styles.UpVote}>{userdata.upvotes.length}</Text> </View> <View style={styles.verticalLine}></View> <View style={styles.Postrow1}> <Text style={styles.followerTxt}>DownVotes</Text> <Text style={styles.UpVote}>{userdata.donwvotes.length}</Text> </View> <View style={styles.verticalLine}></View> <View style={styles.Postrow1}> <Text style={styles.followerTxt}>Posts</Text> <Text style={styles.UpVote}>{userdata.posts.length}</Text> </View> </View> {/* <Text style={styles.decs}>Hello this is des</Text> */} </View> { userdata.posts.length > 0 ? <View style={styles.section1}> <Text style={styles.postTxt}>Your Posts</Text> <View style={styles.posts}> { userdata.posts.map((item) => { return ( <Image key={item.id} style={styles.Postimage} source={{ uri: item.posts }} /> ) }) } </View> </View> : <View style={styles.noPost}> <Text style={styles.noposttxt}>User not posted anything yet</Text> </View> } </ScrollView> : <ActivityIndicator color='white' size='large' /> } </View> ) } export default Profile
后端/userdata接口代码
router.post('/userdata', (req, res) => { const { authorization } = req.headers; if (!authorization) { return res.status(401).json({ error: 'You must be logged in, token not given' }); } const token = authorization.replace("Bearer", ""); console.log(token); jwt.verify(token, process.env.JWT_SECERT, (err, payload) => { if (err) { return res.status(401).json({ error: 'You must be logged in, token invalid' }) } const { _id } = payload; User.findById(_id).then( userdata => { res.status(200).send({ message: 'User Found', user: userdata }) }) }) })
登录逻辑代码
const handleLogin = () => { if (email == '' || password == '') { alert('Please enter email and password') } else { setLoading(true) fetch('http://10.0.2.2:3000/login', { // for emultor 'http://10.0.2.2:3000/signup method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }) .then(res => res.json()) .then(async data => { if (data.error) { setLoading(false) alert(data.error) } else if (data.message == 'Successfully Signed In') { setLoading(false) await AsyncStorage.setItem('user', JSON.stringify(data)) navigation.navigate('home', { data }) } }) .catch(err => { setLoading(false) alert(err) }) } }
后端/login接口代码
router.post('/login', (req, res) => { const { email, password } = req.body; if (!email || !password) { return res.status(422).json({ error: 'Please fill all the fields' }) } else { User.findOne({ email: email }) .then(savedUser => { if (!savedUser) { return res.status(422).json({ error: 'invaile cnreditnions' }) } else { bcrypt.compare(password, savedUser.password) .then( doMatch => { if (doMatch) { const token = jwt.sign({ _id: savedUser._id }, process.env.JWT_SECERT); const { _id, username, email } = savedUser; res.json({ message: 'Successfully Signed In', token, user: { _id, username, email } }); } else { return res.status(422).json({ error: 'invaile cnreditnions' }) } } ) } }) .catch(err => { console.log(err) }) } })
错误原因及修复方案
1. 核心错误:AsyncStorage返回null导致JSON.parse失败
错误直接出在JSON.parse(value).token,说明AsyncStorage.getItem('user')拿到的value是null——可能是用户未登录直接进入Profile页面,或者登录时存储操作失败。
修复:
在Profile组件的useEffect中先判断value是否存在,再执行后续逻辑,同时避免重复JSON.parse:
useEffect(() => { AsyncStorage.getItem('user') .then(async (value) => { if (!value) { alert('请先登录') navigation.navigate('login') return } const savedUser = JSON.parse(value) fetch('http://10.0.2.2:3000/userdata', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + savedUser.token }, body: JSON.stringify({ email: savedUser.user.email }) }) .then(res => res.json()) .then(data => { if (data.message === 'User Found') { setUserdata(data.user) } else { alert('获取用户数据失败') navigation.navigate('login') } }) .catch(err => { alert(err.message) console.log(err) }) }) .catch(err => { alert(err.message) console.log(err) }) }, [])
2. Authorization头格式不规范
后端用authorization.replace("Bearer", "")截取token,但前端原代码是'Bearer' + token(无空格),会导致token前带有多余字符,引发JWT验证失败。
修复:
前端Authorization头改成'Bearer ' + savedUser.token(Bearer后加空格,符合JWT规范),后端也可以同步调整为replace("Bearer ", ""),匹配更准确。
3. 字符串匹配错误
Profile组件中判断data.message == 'User Data Fetched Susscessfully',但后端/userdata接口返回的是{ message: 'User Found' },两者不匹配会导致误跳登录页。
修复:
将判断条件改为data.message === 'User Found'。
4. 拼写错误
Profile组件中userdata.donwvotes.length是拼写错误,应为userdata.downvotes.length,否则会触发新的类型错误。
内容的提问来源于stack exchange,提问作者user20785876

