React Context返回null但useEffect返回对象,创建任务报user.id未定义
问题根因及修复方案
核心问题1:变量声明顺序错误
你在调用useState初始化target的时候,useAuth的解构赋值还没执行,此时user属于未声明变量,自然拿不到user.id的值。
核心问题2:state初始值绑定静态值,不会跟随Context更新
就算调整了声明顺序,user从Context拿到最新值后,已经初始化完成的state不会自动更新_partition的值。
核心问题3:state更新时丢失原有属性
React的useState setter不会自动合并对象属性,你在descriptionOnChange里只传入{description: value},会直接覆盖掉原有state里的_partition、_id等所有其他属性。
额外的打印日志问题
useEffect里用模板字符串包裹user对象,会自动调用对象的toString()方法,所以输出[object Object],直接写console.log('from create target', user)就能打印对象的实际内容。
修复后的代码
import React, {FC, SetStateAction, useEffect, useRef, useState} from 'react'; import {Text, View} from 'react-native'; import TButton from '../../components/button'; import Input from '../../components/input'; import {useAuth} from '../../lib/realmProvider'; import {useRealm} from '../../lib/syncProvider'; import {ITarget} from '../../lib/taskInterface'; import {Target} from '../../realm/taskSchema'; import {ObjectId} from 'bson'; const CreateTaskScreen: FC = () => { // 先调用useAuth拿到user,再初始化state const {user} = useAuth(); const realm = useRealm(); const [target, setTarget] = useState<Partial<ITarget>>({ _id: '', _partition: '', // 初始值留空,等user加载完成后再更新 description: '', status: false, createAt: new Date(Date.now()).toString(), updateAt: '', }); // 监听user变化,更新state里的_partition useEffect(() => { if(user?.id) { setTarget(prev => ({...prev, _partition: user.id})); } console.log('from create target', user); }, [user]); const targetHandler = () => { // 提交前先校验_partition是否存在 if(!target._partition) return console.log('用户信息未加载完成,请稍后重试'); try { realm.write(() => { realm.create<Target>('Targets', { _id: new ObjectId(), _partition: target._partition, description: target.description, status: target.status, createAt: target.createAt, updateAt: target.updateAt, }); }); } catch (err) { console.log(err); throw err; } }; const testHandler = () => { console.log(user); }; const descriptionOnChange = (e: {nativeEvent: {text: SetStateAction}}) => { let value = e.nativeEvent.text; // 更新state时展开原有属性,避免丢失 setTarget(prev => ({...prev, description: value})); }; return ( <View> <Text>Create a new Task</Text> <Input placeholder={'Targe Description'} onChange={descriptionOnChange} value={target.description} multiline={true} /> <TButton title={'Add Target'} onPress={targetHandler} /> <TButton title={'Test Button'} onPress={testHandler} /> </View> ); }; export default CreateTaskScreen;
内容的提问来源于stack exchange,提问作者Tony Ngomana
相关产品推荐
相关产品推荐

