刷新页面时反应挂钩上下文状态未定义
react hooks context state is undefined when refreshing the page
我正在创建一个社交媒体应用程序,当我与用户一起登录时,我将令牌保存在本地存储中,并将用户信息置于上下文中,以便之后在多个组件中使用它,以及它的工作,但是当我刷新页面时,数据消失并且上下文未定义。我做错了什么?
我的App.js
function App() {
const [userData, setUserData] = useState({
name: "",
lastname: "",
username: "",
email: "",
});
return (
<Router>
<userContext.Provider value={{ userData, setUserData }}>
<div className="app">
<Switch>
<Route exact path="/" component={Login} />
<Route path="/register" component={Register} />
<Route path="/home" component={Home} />
<Route path="/profile" component={Profile} />
</Switch>
</div>
</userContext.Provider>
</Router>
);
}
我的Login.js
function Login() {
const history = useHistory()
const {userData, setUserData} = useContext(userContext)
const [loginUser, setLoginUser] = useState({
email: '',
password: ''
})
const [error, setError] = useState()
const {email, password} = loginUser
const handleOnChange = (e) => {
setLoginUser({ ...loginUser, [e.target.name]: e.target.value})
}
const handleOnSubmit = (e) => {
e.preventDefault()
axios.post("http://localhost:5000/login", loginUser)
.then((res) => {
setUserData({
name: res.data.user.name,
lastname: res.data.user.lastname,
username: res.data.user.username,
email: res.data.user.email,
})
localStorage.setItem("auth-token", res.data.token)
history.push("/home")
})
.catch(err => {
err.response.data.msg && setError(err.response.data.msg)
})
}
return (
<div className="login">
<div>
<form onSubmit={handleOnSubmit} className="login-form">
{error ? <h4 className='login-error'>{error}</h4> : ""}
<input type="email" placeholder="Email or username" value={email} name='email' onChange={e => handleOnChange(e)}/>
<input type="password" placeholder="Password" value={password} name='password' onChange={e => handleOnChange(e)}/>
<Button type="submit" variant="contained">Log in</Button>
<div></div>
<p>Don't have an account? <Link to="/register">Click here</Link></p>
</form>
<h1>Raise your word <TwitterIcon className="login-right-icon"/></h1>
</div>
</div>
)
}
我的 Home.js 如果我刷新,我会丢失上下文中的数据
function Home() {
const {userData, setUserData} = useContext(userContext)
const [posts, setPost] = useState([])
const [createPost, setCreatePost] = useState('')
const handleToken = () => {
localStorage.removeItem('auth-token')
}
const token = localStorage.getItem("auth-token");
const handleOnSubmit = (e) => {
e.preventDefault()
axios.post('http://localhost:5000/posts', {textOfThePost: createPost}, {
headers: { 'auth-token': token },
})
.then((res) => {setCreatePost("")})
}
useEffect(() => {
axios.get('http://localhost:5000/posts')
.then(res => {
setPost(res.data)
})
}, [createPost])
return (
<div className="home">
<div style={{display: 'flex', alignItems: 'center'}}>
<h1>this is the home: Welcome, {userData.username}</h1>
<Link style={{margin: 10}} to="/home">home</Link>
<Link style={{margin: 10}} to="/profile">profile</Link>
<Link style={{margin: 10}} onClick={handleToken} to="/">log out</Link>
</div>
<form onSubmit={handleOnSubmit}>
<input type="text" placeholder="What's happening?" value={createPost} onChange={e => setCreatePost(e.target.value)}/>
<button type="submit">tweet</button>
</form>
<div style={{display: 'flex', flexDirection: 'column'}}>
{posts.map(post => (
<div style={{border: '2px solid black', marginBottom: 10, marginRight: 'auto', marginLeft: 'auto', width: 300}} key={post._id}>
<div style={{display: 'flex', alignItems: 'center'}}>
<Avatar src={post.avatar}/>
<span style={{color: 'blue', marginLeft: 10}}>{post.name} <span style={{color: 'grey', fontSize: 11}}>@{post?.username}</span></span><br/>
</div>
<span>{post.textOfThePost}</span><br/>
<span>{moment(post.date).format('lll')}</span>
</div>
)).reverse()}
</div>
</div>
)
}
您只将 token
存储在 localStorage
中,因此没有理由也保存上下文。
如果你确实想保存userData
,你可以将它保存在localStorage
(或使用任何其他状态管理方式):
function Login() {
// irrelevant code
const handleOnSubmit = (e) => {
e.preventDefault()
axios.post("http://localhost:5000/login", loginUser)
.then((res) => {
const { name, lastname, username, email } = res.data.user;
const newUserData = { name, lastname, username, email };
setUserData(newUserData);
localStorage.setItem('user-data', JSON.stringify(newUserData));
// irrelevant code
});
}
// irrelevant code
}
然后在 App
的 useState
调用中使用它:
function App() {
const persistentUserData = localStorage.getItem('user-data');
const [userData, setUserData] = useState(JSON.parse(persistentUserData));
// return
}
此类 JS 应用程序中的状态不会在页面刷新之间自动保留。因此需要 localstorage / sessionstorage / indexdb 和类似的机制。您将需要保存状态并在组件加载时检索它。
例如,您可以修改 home
组件以使用如下挂钩保存/检索数据:
function App() {
// 1. Create a key to name your data in local storage
const USER_DATA_KEY_IN_LOCALSTORAGE = 'user_data';
const [userData, setUserData] = useState({
name: "",
lastname: "",
username: "",
email: "",
});
// 2. Retrieve userData from local storage on startup
useEffect(() => {
const userDataString = window.localStorage.getItem(USER_DATA_KEY_IN_LOCALSTORAGE);
setUserData(JSON.parse(userDataString));
}, []);
// 3. Update userData in local storage when it changes.
useEffect(() => {
window.localStorage.setItem(USER_DATA_KEY_IN_LOCALSTORAGE, JSON.stringify(userData));
}, [userData]);
return (
<Router>
<userContext.Provider value={{ userData, setUserData }}>
<div className="app">
<Switch>
<Route exact path="/" component={Login} />
<Route path="/register" component={Register} />
<Route path="/home" component={Home} />
<Route path="/profile" component={Profile} />
</Switch>
</div>
</userContext.Provider>
</Router>
);
}
当然,您需要处理 userData 不存在且 JSON.parse() 抛出错误和类似内容的情况。
我正在创建一个社交媒体应用程序,当我与用户一起登录时,我将令牌保存在本地存储中,并将用户信息置于上下文中,以便之后在多个组件中使用它,以及它的工作,但是当我刷新页面时,数据消失并且上下文未定义。我做错了什么?
我的App.js
function App() {
const [userData, setUserData] = useState({
name: "",
lastname: "",
username: "",
email: "",
});
return (
<Router>
<userContext.Provider value={{ userData, setUserData }}>
<div className="app">
<Switch>
<Route exact path="/" component={Login} />
<Route path="/register" component={Register} />
<Route path="/home" component={Home} />
<Route path="/profile" component={Profile} />
</Switch>
</div>
</userContext.Provider>
</Router>
);
}
我的Login.js
function Login() {
const history = useHistory()
const {userData, setUserData} = useContext(userContext)
const [loginUser, setLoginUser] = useState({
email: '',
password: ''
})
const [error, setError] = useState()
const {email, password} = loginUser
const handleOnChange = (e) => {
setLoginUser({ ...loginUser, [e.target.name]: e.target.value})
}
const handleOnSubmit = (e) => {
e.preventDefault()
axios.post("http://localhost:5000/login", loginUser)
.then((res) => {
setUserData({
name: res.data.user.name,
lastname: res.data.user.lastname,
username: res.data.user.username,
email: res.data.user.email,
})
localStorage.setItem("auth-token", res.data.token)
history.push("/home")
})
.catch(err => {
err.response.data.msg && setError(err.response.data.msg)
})
}
return (
<div className="login">
<div>
<form onSubmit={handleOnSubmit} className="login-form">
{error ? <h4 className='login-error'>{error}</h4> : ""}
<input type="email" placeholder="Email or username" value={email} name='email' onChange={e => handleOnChange(e)}/>
<input type="password" placeholder="Password" value={password} name='password' onChange={e => handleOnChange(e)}/>
<Button type="submit" variant="contained">Log in</Button>
<div></div>
<p>Don't have an account? <Link to="/register">Click here</Link></p>
</form>
<h1>Raise your word <TwitterIcon className="login-right-icon"/></h1>
</div>
</div>
)
}
我的 Home.js 如果我刷新,我会丢失上下文中的数据
function Home() {
const {userData, setUserData} = useContext(userContext)
const [posts, setPost] = useState([])
const [createPost, setCreatePost] = useState('')
const handleToken = () => {
localStorage.removeItem('auth-token')
}
const token = localStorage.getItem("auth-token");
const handleOnSubmit = (e) => {
e.preventDefault()
axios.post('http://localhost:5000/posts', {textOfThePost: createPost}, {
headers: { 'auth-token': token },
})
.then((res) => {setCreatePost("")})
}
useEffect(() => {
axios.get('http://localhost:5000/posts')
.then(res => {
setPost(res.data)
})
}, [createPost])
return (
<div className="home">
<div style={{display: 'flex', alignItems: 'center'}}>
<h1>this is the home: Welcome, {userData.username}</h1>
<Link style={{margin: 10}} to="/home">home</Link>
<Link style={{margin: 10}} to="/profile">profile</Link>
<Link style={{margin: 10}} onClick={handleToken} to="/">log out</Link>
</div>
<form onSubmit={handleOnSubmit}>
<input type="text" placeholder="What's happening?" value={createPost} onChange={e => setCreatePost(e.target.value)}/>
<button type="submit">tweet</button>
</form>
<div style={{display: 'flex', flexDirection: 'column'}}>
{posts.map(post => (
<div style={{border: '2px solid black', marginBottom: 10, marginRight: 'auto', marginLeft: 'auto', width: 300}} key={post._id}>
<div style={{display: 'flex', alignItems: 'center'}}>
<Avatar src={post.avatar}/>
<span style={{color: 'blue', marginLeft: 10}}>{post.name} <span style={{color: 'grey', fontSize: 11}}>@{post?.username}</span></span><br/>
</div>
<span>{post.textOfThePost}</span><br/>
<span>{moment(post.date).format('lll')}</span>
</div>
)).reverse()}
</div>
</div>
)
}
您只将 token
存储在 localStorage
中,因此没有理由也保存上下文。
如果你确实想保存userData
,你可以将它保存在localStorage
(或使用任何其他状态管理方式):
function Login() {
// irrelevant code
const handleOnSubmit = (e) => {
e.preventDefault()
axios.post("http://localhost:5000/login", loginUser)
.then((res) => {
const { name, lastname, username, email } = res.data.user;
const newUserData = { name, lastname, username, email };
setUserData(newUserData);
localStorage.setItem('user-data', JSON.stringify(newUserData));
// irrelevant code
});
}
// irrelevant code
}
然后在 App
的 useState
调用中使用它:
function App() {
const persistentUserData = localStorage.getItem('user-data');
const [userData, setUserData] = useState(JSON.parse(persistentUserData));
// return
}
此类 JS 应用程序中的状态不会在页面刷新之间自动保留。因此需要 localstorage / sessionstorage / indexdb 和类似的机制。您将需要保存状态并在组件加载时检索它。
例如,您可以修改 home
组件以使用如下挂钩保存/检索数据:
function App() {
// 1. Create a key to name your data in local storage
const USER_DATA_KEY_IN_LOCALSTORAGE = 'user_data';
const [userData, setUserData] = useState({
name: "",
lastname: "",
username: "",
email: "",
});
// 2. Retrieve userData from local storage on startup
useEffect(() => {
const userDataString = window.localStorage.getItem(USER_DATA_KEY_IN_LOCALSTORAGE);
setUserData(JSON.parse(userDataString));
}, []);
// 3. Update userData in local storage when it changes.
useEffect(() => {
window.localStorage.setItem(USER_DATA_KEY_IN_LOCALSTORAGE, JSON.stringify(userData));
}, [userData]);
return (
<Router>
<userContext.Provider value={{ userData, setUserData }}>
<div className="app">
<Switch>
<Route exact path="/" component={Login} />
<Route path="/register" component={Register} />
<Route path="/home" component={Home} />
<Route path="/profile" component={Profile} />
</Switch>
</div>
</userContext.Provider>
</Router>
);
}
当然,您需要处理 userData 不存在且 JSON.parse() 抛出错误和类似内容的情况。