即使在反应挂钩中使用 useContext() 后,值也不会传递和显示
Values are not passing and displaying even after using useContext() in react hooks
我使用 useContext()
在 Navigation.js
中获取类似 name and photo
的值。我在 Profile.js
中设置了 <UserProfileContext.Provider value={{ updateProfile, setUpdateProfile}}>
。但是 Navigation.js >> {updateProfile.name}|
中仍然没有显示值
App.js
import React, { useState } from 'react';
import { BrowserRouter, Route, Switch } from "react-router-dom";
import Home from "./components/Home";
import Register from "./components/Register";
import Login from "./components/Login";
import Aboutus from "./components/Aboutus";
import Navigation from "./components/Navigation";
import Profile from "./components/Profile";
import ErrorPage from "./components/ErrorPage";
import { ProtectedRoute } from "./components/protected.route";
import UserProfileContext from './context';
var ReactDOM = require("react-dom");
const App = () => {
return (
<BrowserRouter>
<>
<Navigation />
<Switch>
<ProtectedRoute exact path="/" component={Home} />
<ProtectedRoute path="/profile" component={Profile} />
<ProtectedRoute path="/aboutus" component={Aboutus} />
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
<Route exact path="*" component={ErrorPage} />
</Switch>
</>
</BrowserRouter>
);
};
ReactDOM.render(
React.createElement(App, null),
document.getElementById("root")
);
export default App;
Navigation.js
import React, { useContext } from 'react';
import { NavLink, useHistory } from 'react-router-dom';
import UserProfileContext from '../context';
const Navigation = () => {
const history = useHistory();
const { updateProfile } = useContext(UserProfileContext);
const divStyle = {
float:'left',
color: '#64cad8',
padding: '0px 0px 0px 10px',
font:'Lucida, sans-serif'
};
function logout() {
localStorage.removeItem('loginEmail')
localStorage.removeItem('Privilege')
history.push('/login')
window.location.reload(true);
}
return localStorage.getItem('loginEmail') &&
<div className="App">
<div className="wrapper">
<nav className="siteNavigation_nav_links">
<div className="clubLogo landing"style={divStyle}><b>Southside Soccer</b></div>
<NavLink className="mobile_register_link" to="/">Home</NavLink>
<NavLink className="mobile_register_link" to="/profile">Profile</NavLink>
<NavLink className="mobile_login_link" to="/login" onClick={logout}>Logout</NavLink>
<NavLink className="mobile_login_link" to='/aboutus'>About us</NavLink>
<div className="profileImage nav menu">
<span>{updateProfile.name}</span>|<img src={updateProfile.photo}></img>
</div>
</nav>
</div>
</div>
}
export default Navigation;
context.js
import React from 'react';
export default React.createContext();
Profile.js
import React, {useEffect, useState } from "react";
import { useForm } from 'react-hook-form';
import { useHistory } from "react-router-dom";
import Axios from "axios";
import UserProfileContext from '../context';
const Profile = () => {
const [email, setEmail] = useState('');
const [picture, setPicture] = useState('');
const [playerProfile, setPlayerProfile] = useState([]);
const loginUserEmail = localStorage.getItem('loginEmail');
const [updateProfile, setUpdateProfile] = useState({ _id: '', photo: '', name: '', email:''})
const [isSent, setIsSent] = useState(false);
const [helperText, setHelperText] = useState('');
const [disabled, setDisabled] = useState(true);
const { handleSubmit, register, errors } = useForm();
const history = useHistory();
const onChangePicture = e => {
console.log('picture: ', picture);
if (e.target.files.length) {
setPicture(URL.createObjectURL(e.target.files[0]));
} else {
return false;
}
};
// If no profile image is being uploaded, to avoid the broken display of image, display a default image.
const addDefaultSrc = e => {
e.target.src = '/images/default-icon.png';
}
// Pass the id to the handler so you will know which item id changing.
const handleChange = (e, id) => {
e.persist();
let itemIndex;
const targetPlayer = playerProfile.find((player, index) => {
console.log({ player, id, index });
itemIndex = index;
return player.id === id;
});
console.log({ targetPlayer, id, e });
const editedTarget = {
...targetPlayer,
[e.target.name]: e.target.value
};
const tempPlayers = Array.from(playerProfile);
tempPlayers[itemIndex] = editedTarget;
setPlayerProfile(tempPlayers);
setUpdateProfile({ ...updateProfile, [e.target.name]: e.target.value }); // this is added just to see if its working
};
useEffect(() => {
const fetchData = async () => {
try {
const params = {
email: loginUserEmail,
};
const res = await Axios.get('http://localhost:8000/service/profile', {params});
setPlayerProfile(res.data.playerProfile);
} catch (e) {
console.log(e);
}
}
fetchData();
}, []);
const onSubmit = () => {
setDisabled(disabled);
const fetchData = async () => {
try {
const params = {
email: loginUserEmail,
};
const data = {photo: updateProfile.photo, name: updateProfile.name, email: updateProfile.email}
const res = await Axios.put('http://localhost:8000/service/profile', data, {params});
console.log("Front End update message:" + res.data.success);
if (res.data.success) {
setIsSent(true);
history.push('/')
}
else {
console.log(res.data.message);
setHelperText(res.data.message);
}
} catch (e) {
setHelperText(e.response.data.message);
}
}
fetchData();
}
return (
<UserProfileContext.Provider value={{ updateProfile, setUpdateProfile}}>
<div className="register_wrapper">
<div className="register_player_column_layout_one">
<div className="register_player_Twocolumn_layout_two">
<form onSubmit={handleSubmit(onSubmit)} className="myForm">
{
playerProfile.map(({ id, photo, name, email}) => (
<div key={id}>
<div className="formInstructionsDiv formElement">
<h2 className="formTitle">Profile</h2>
<div className="register_profile_image">
<input id="profilePic" name="photo" type="file" onChange={onChangePicture} />
</div>
<div className="previewProfilePic" >
<img alt="" onError={addDefaultSrc} name="previewImage" className="playerProfilePic_home_tile" src={photo} onChange={e => handleChange(e, id)}></img>
</div>
</div>
<div className="fillContentDiv formElement">
<label>
<input className="inputRequest formContentElement" name="name" type="text" value={name}
onChange={e => handleChange(e, id)}
maxLength={30}
ref={register({
required: "Full name is required",
pattern: {
value: /^[a-zA-Z\s]{3,30}$/,
message: "Full name should have minimum of 3 letters"
}
})}
/>
<span className="registerErrorTextFormat">{errors.name && errors.name.message}</span>
</label>
<label>
<input className="inputRequest formContentElement" name="email" type="text" value={email}
onChange={e => handleChange(e, id)}
disabled={disabled}
/>
</label>
</div>
<label>
<span className="profileValidationText">{helperText}</span>
</label>
<div className="submitButtonDiv formElement">
<button type="submit" className="submitButton">Save</button>
</div>
</div>
))
}
</form>
</div>
</div>
</div>
</UserProfileContext.Provider>
);
}
export default Profile;
导航组件需要将 ContextProvider 放在层次结构中,但它不需要,因为 Provider 是在配置文件组件中呈现的。
您必须将 Provider 的使用移到一个单独的组件中,并将其呈现为 Navigation 和 Profile 的组件祖先。 Post 您可以在 Navigation 和 Profile 中使用 UserContext
UserProfileProvider.js
import UserProfileContext from '../context';
const UserProfileProvider = ({children}) => {
const [updateProfile, setUpdateProfile] = useState({ _id: '', photo: '', name: '', email:''});
const value = useMemo(() => ({
updateProfile, setUpdateProfile
}), [updateProfile]);
return (
<UserProfileContext.Provider value={value}>
{children}
</UserProfileContext.Provider>
)
}
App.js
import UserProfileProvider from './UserProfileProvider.js';
const App = () => {
return (
<BrowserRouter>
<UserProfileProvider>
<Navigation />
<Switch>
<ProtectedRoute exact path="/" component={Home} />
<ProtectedRoute path="/profile" component={Profile} />
<ProtectedRoute path="/aboutus" component={Aboutus} />
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
<Route exact path="*" component={ErrorPage} />
</Switch>
</UserProfileProvider>
</BrowserRouter>
);
};
Profile.js
import UserProfileContext from '../context';
const Profile = () => {
const [email, setEmail] = useState('');
const [picture, setPicture] = useState('');
const [playerProfile, setPlayerProfile] = useState([]);
const loginUserEmail = localStorage.getItem('loginEmail');
const {updateProfile, setUpdateProfile} = useContext(UserProfileContext);
const [isSent, setIsSent] = useState(false);
const [helperText, setHelperText] = useState('');
const [disabled, setDisabled] = useState(true);
const { handleSubmit, register, errors } = useForm();
const history = useHistory();
const onChangePicture = e => {
console.log('picture: ', picture);
if (e.target.files.length) {
setPicture(URL.createObjectURL(e.target.files[0]));
} else {
return false;
}
};
// If no profile image is being uploaded, to avoid the broken display of image, display a default image.
const addDefaultSrc = e => {
e.target.src = '/images/default-icon.png';
}
// Pass the id to the handler so you will know which item id changing.
const handleChange = (e, id) => {
e.persist();
let itemIndex;
const targetPlayer = playerProfile.find((player, index) => {
console.log({ player, id, index });
itemIndex = index;
return player.id === id;
});
console.log({ targetPlayer, id, e });
const editedTarget = {
...targetPlayer,
[e.target.name]: e.target.value
};
const tempPlayers = Array.from(playerProfile);
tempPlayers[itemIndex] = editedTarget;
setPlayerProfile(tempPlayers);
setUpdateProfile({ ...updateProfile, [e.target.name]: e.target.value }); // this is added just to see if its working
};
useEffect(() => {
const fetchData = async () => {
try {
const params = {
email: loginUserEmail,
};
const res = await Axios.get('http://localhost:8000/service/profile', {params});
setPlayerProfile(res.data.playerProfile);
} catch (e) {
console.log(e);
}
}
fetchData();
}, []);
const onSubmit = () => {
setDisabled(disabled);
const fetchData = async () => {
try {
const params = {
email: loginUserEmail,
};
const data = {photo: updateProfile.photo, name: updateProfile.name, email: updateProfile.email}
const res = await Axios.put('http://localhost:8000/service/profile', data, {params});
console.log("Front End update message:" + res.data.success);
if (res.data.success) {
setIsSent(true);
history.push('/')
}
else {
console.log(res.data.message);
setHelperText(res.data.message);
}
} catch (e) {
setHelperText(e.response.data.message);
}
}
fetchData();
}
return (
<div className="register_wrapper">
<div className="register_player_column_layout_one">
<div className="register_player_Twocolumn_layout_two">
<form onSubmit={handleSubmit(onSubmit)} className="myForm">
{
playerProfile.map(({ id, photo, name, email}) => (
<div key={id}>
<div className="formInstructionsDiv formElement">
<h2 className="formTitle">Profile</h2>
<div className="register_profile_image">
<input id="profilePic" name="photo" type="file" onChange={onChangePicture} />
</div>
<div className="previewProfilePic" >
<img alt="" onError={addDefaultSrc} name="previewImage" className="playerProfilePic_home_tile" src={photo} onChange={e => handleChange(e, id)}></img>
</div>
</div>
<div className="fillContentDiv formElement">
<label>
<input className="inputRequest formContentElement" name="name" type="text" value={name}
onChange={e => handleChange(e, id)}
maxLength={30}
ref={register({
required: "Full name is required",
pattern: {
value: /^[a-zA-Z\s]{3,30}$/,
message: "Full name should have minimum of 3 letters"
}
})}
/>
<span className="registerErrorTextFormat">{errors.name && errors.name.message}</span>
</label>
<label>
<input className="inputRequest formContentElement" name="email" type="text" value={email}
onChange={e => handleChange(e, id)}
disabled={disabled}
/>
</label>
</div>
<label>
<span className="profileValidationText">{helperText}</span>
</label>
<div className="submitButtonDiv formElement">
<button type="submit" className="submitButton">Save</button>
</div>
</div>
))
}
</form>
</div>
</div>
</div>
);
}
export default Profile;
我使用 useContext()
在 Navigation.js
中获取类似 name and photo
的值。我在 Profile.js
中设置了 <UserProfileContext.Provider value={{ updateProfile, setUpdateProfile}}>
。但是 Navigation.js >> {updateProfile.name}|
App.js
import React, { useState } from 'react';
import { BrowserRouter, Route, Switch } from "react-router-dom";
import Home from "./components/Home";
import Register from "./components/Register";
import Login from "./components/Login";
import Aboutus from "./components/Aboutus";
import Navigation from "./components/Navigation";
import Profile from "./components/Profile";
import ErrorPage from "./components/ErrorPage";
import { ProtectedRoute } from "./components/protected.route";
import UserProfileContext from './context';
var ReactDOM = require("react-dom");
const App = () => {
return (
<BrowserRouter>
<>
<Navigation />
<Switch>
<ProtectedRoute exact path="/" component={Home} />
<ProtectedRoute path="/profile" component={Profile} />
<ProtectedRoute path="/aboutus" component={Aboutus} />
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
<Route exact path="*" component={ErrorPage} />
</Switch>
</>
</BrowserRouter>
);
};
ReactDOM.render(
React.createElement(App, null),
document.getElementById("root")
);
export default App;
Navigation.js
import React, { useContext } from 'react';
import { NavLink, useHistory } from 'react-router-dom';
import UserProfileContext from '../context';
const Navigation = () => {
const history = useHistory();
const { updateProfile } = useContext(UserProfileContext);
const divStyle = {
float:'left',
color: '#64cad8',
padding: '0px 0px 0px 10px',
font:'Lucida, sans-serif'
};
function logout() {
localStorage.removeItem('loginEmail')
localStorage.removeItem('Privilege')
history.push('/login')
window.location.reload(true);
}
return localStorage.getItem('loginEmail') &&
<div className="App">
<div className="wrapper">
<nav className="siteNavigation_nav_links">
<div className="clubLogo landing"style={divStyle}><b>Southside Soccer</b></div>
<NavLink className="mobile_register_link" to="/">Home</NavLink>
<NavLink className="mobile_register_link" to="/profile">Profile</NavLink>
<NavLink className="mobile_login_link" to="/login" onClick={logout}>Logout</NavLink>
<NavLink className="mobile_login_link" to='/aboutus'>About us</NavLink>
<div className="profileImage nav menu">
<span>{updateProfile.name}</span>|<img src={updateProfile.photo}></img>
</div>
</nav>
</div>
</div>
}
export default Navigation;
context.js
import React from 'react';
export default React.createContext();
Profile.js
import React, {useEffect, useState } from "react";
import { useForm } from 'react-hook-form';
import { useHistory } from "react-router-dom";
import Axios from "axios";
import UserProfileContext from '../context';
const Profile = () => {
const [email, setEmail] = useState('');
const [picture, setPicture] = useState('');
const [playerProfile, setPlayerProfile] = useState([]);
const loginUserEmail = localStorage.getItem('loginEmail');
const [updateProfile, setUpdateProfile] = useState({ _id: '', photo: '', name: '', email:''})
const [isSent, setIsSent] = useState(false);
const [helperText, setHelperText] = useState('');
const [disabled, setDisabled] = useState(true);
const { handleSubmit, register, errors } = useForm();
const history = useHistory();
const onChangePicture = e => {
console.log('picture: ', picture);
if (e.target.files.length) {
setPicture(URL.createObjectURL(e.target.files[0]));
} else {
return false;
}
};
// If no profile image is being uploaded, to avoid the broken display of image, display a default image.
const addDefaultSrc = e => {
e.target.src = '/images/default-icon.png';
}
// Pass the id to the handler so you will know which item id changing.
const handleChange = (e, id) => {
e.persist();
let itemIndex;
const targetPlayer = playerProfile.find((player, index) => {
console.log({ player, id, index });
itemIndex = index;
return player.id === id;
});
console.log({ targetPlayer, id, e });
const editedTarget = {
...targetPlayer,
[e.target.name]: e.target.value
};
const tempPlayers = Array.from(playerProfile);
tempPlayers[itemIndex] = editedTarget;
setPlayerProfile(tempPlayers);
setUpdateProfile({ ...updateProfile, [e.target.name]: e.target.value }); // this is added just to see if its working
};
useEffect(() => {
const fetchData = async () => {
try {
const params = {
email: loginUserEmail,
};
const res = await Axios.get('http://localhost:8000/service/profile', {params});
setPlayerProfile(res.data.playerProfile);
} catch (e) {
console.log(e);
}
}
fetchData();
}, []);
const onSubmit = () => {
setDisabled(disabled);
const fetchData = async () => {
try {
const params = {
email: loginUserEmail,
};
const data = {photo: updateProfile.photo, name: updateProfile.name, email: updateProfile.email}
const res = await Axios.put('http://localhost:8000/service/profile', data, {params});
console.log("Front End update message:" + res.data.success);
if (res.data.success) {
setIsSent(true);
history.push('/')
}
else {
console.log(res.data.message);
setHelperText(res.data.message);
}
} catch (e) {
setHelperText(e.response.data.message);
}
}
fetchData();
}
return (
<UserProfileContext.Provider value={{ updateProfile, setUpdateProfile}}>
<div className="register_wrapper">
<div className="register_player_column_layout_one">
<div className="register_player_Twocolumn_layout_two">
<form onSubmit={handleSubmit(onSubmit)} className="myForm">
{
playerProfile.map(({ id, photo, name, email}) => (
<div key={id}>
<div className="formInstructionsDiv formElement">
<h2 className="formTitle">Profile</h2>
<div className="register_profile_image">
<input id="profilePic" name="photo" type="file" onChange={onChangePicture} />
</div>
<div className="previewProfilePic" >
<img alt="" onError={addDefaultSrc} name="previewImage" className="playerProfilePic_home_tile" src={photo} onChange={e => handleChange(e, id)}></img>
</div>
</div>
<div className="fillContentDiv formElement">
<label>
<input className="inputRequest formContentElement" name="name" type="text" value={name}
onChange={e => handleChange(e, id)}
maxLength={30}
ref={register({
required: "Full name is required",
pattern: {
value: /^[a-zA-Z\s]{3,30}$/,
message: "Full name should have minimum of 3 letters"
}
})}
/>
<span className="registerErrorTextFormat">{errors.name && errors.name.message}</span>
</label>
<label>
<input className="inputRequest formContentElement" name="email" type="text" value={email}
onChange={e => handleChange(e, id)}
disabled={disabled}
/>
</label>
</div>
<label>
<span className="profileValidationText">{helperText}</span>
</label>
<div className="submitButtonDiv formElement">
<button type="submit" className="submitButton">Save</button>
</div>
</div>
))
}
</form>
</div>
</div>
</div>
</UserProfileContext.Provider>
);
}
export default Profile;
导航组件需要将 ContextProvider 放在层次结构中,但它不需要,因为 Provider 是在配置文件组件中呈现的。
您必须将 Provider 的使用移到一个单独的组件中,并将其呈现为 Navigation 和 Profile 的组件祖先。 Post 您可以在 Navigation 和 Profile 中使用 UserContext
UserProfileProvider.js
import UserProfileContext from '../context';
const UserProfileProvider = ({children}) => {
const [updateProfile, setUpdateProfile] = useState({ _id: '', photo: '', name: '', email:''});
const value = useMemo(() => ({
updateProfile, setUpdateProfile
}), [updateProfile]);
return (
<UserProfileContext.Provider value={value}>
{children}
</UserProfileContext.Provider>
)
}
App.js
import UserProfileProvider from './UserProfileProvider.js';
const App = () => {
return (
<BrowserRouter>
<UserProfileProvider>
<Navigation />
<Switch>
<ProtectedRoute exact path="/" component={Home} />
<ProtectedRoute path="/profile" component={Profile} />
<ProtectedRoute path="/aboutus" component={Aboutus} />
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
<Route exact path="*" component={ErrorPage} />
</Switch>
</UserProfileProvider>
</BrowserRouter>
);
};
Profile.js
import UserProfileContext from '../context';
const Profile = () => {
const [email, setEmail] = useState('');
const [picture, setPicture] = useState('');
const [playerProfile, setPlayerProfile] = useState([]);
const loginUserEmail = localStorage.getItem('loginEmail');
const {updateProfile, setUpdateProfile} = useContext(UserProfileContext);
const [isSent, setIsSent] = useState(false);
const [helperText, setHelperText] = useState('');
const [disabled, setDisabled] = useState(true);
const { handleSubmit, register, errors } = useForm();
const history = useHistory();
const onChangePicture = e => {
console.log('picture: ', picture);
if (e.target.files.length) {
setPicture(URL.createObjectURL(e.target.files[0]));
} else {
return false;
}
};
// If no profile image is being uploaded, to avoid the broken display of image, display a default image.
const addDefaultSrc = e => {
e.target.src = '/images/default-icon.png';
}
// Pass the id to the handler so you will know which item id changing.
const handleChange = (e, id) => {
e.persist();
let itemIndex;
const targetPlayer = playerProfile.find((player, index) => {
console.log({ player, id, index });
itemIndex = index;
return player.id === id;
});
console.log({ targetPlayer, id, e });
const editedTarget = {
...targetPlayer,
[e.target.name]: e.target.value
};
const tempPlayers = Array.from(playerProfile);
tempPlayers[itemIndex] = editedTarget;
setPlayerProfile(tempPlayers);
setUpdateProfile({ ...updateProfile, [e.target.name]: e.target.value }); // this is added just to see if its working
};
useEffect(() => {
const fetchData = async () => {
try {
const params = {
email: loginUserEmail,
};
const res = await Axios.get('http://localhost:8000/service/profile', {params});
setPlayerProfile(res.data.playerProfile);
} catch (e) {
console.log(e);
}
}
fetchData();
}, []);
const onSubmit = () => {
setDisabled(disabled);
const fetchData = async () => {
try {
const params = {
email: loginUserEmail,
};
const data = {photo: updateProfile.photo, name: updateProfile.name, email: updateProfile.email}
const res = await Axios.put('http://localhost:8000/service/profile', data, {params});
console.log("Front End update message:" + res.data.success);
if (res.data.success) {
setIsSent(true);
history.push('/')
}
else {
console.log(res.data.message);
setHelperText(res.data.message);
}
} catch (e) {
setHelperText(e.response.data.message);
}
}
fetchData();
}
return (
<div className="register_wrapper">
<div className="register_player_column_layout_one">
<div className="register_player_Twocolumn_layout_two">
<form onSubmit={handleSubmit(onSubmit)} className="myForm">
{
playerProfile.map(({ id, photo, name, email}) => (
<div key={id}>
<div className="formInstructionsDiv formElement">
<h2 className="formTitle">Profile</h2>
<div className="register_profile_image">
<input id="profilePic" name="photo" type="file" onChange={onChangePicture} />
</div>
<div className="previewProfilePic" >
<img alt="" onError={addDefaultSrc} name="previewImage" className="playerProfilePic_home_tile" src={photo} onChange={e => handleChange(e, id)}></img>
</div>
</div>
<div className="fillContentDiv formElement">
<label>
<input className="inputRequest formContentElement" name="name" type="text" value={name}
onChange={e => handleChange(e, id)}
maxLength={30}
ref={register({
required: "Full name is required",
pattern: {
value: /^[a-zA-Z\s]{3,30}$/,
message: "Full name should have minimum of 3 letters"
}
})}
/>
<span className="registerErrorTextFormat">{errors.name && errors.name.message}</span>
</label>
<label>
<input className="inputRequest formContentElement" name="email" type="text" value={email}
onChange={e => handleChange(e, id)}
disabled={disabled}
/>
</label>
</div>
<label>
<span className="profileValidationText">{helperText}</span>
</label>
<div className="submitButtonDiv formElement">
<button type="submit" className="submitButton">Save</button>
</div>
</div>
))
}
</form>
</div>
</div>
</div>
);
}
export default Profile;