tag:ReactJS Context.Provider 值未更新
tag:ReactJS Context.Provider value is not updated
我正在尝试使用 useContext() 但 Provider 不传递该值,即使我使用像这样的假值也是如此:
<TestContext.Provider value="2000">
并保留初始化上下文的默认值:
export const TestContext = createContext(5000);
所以有代码:
父组件
import React, { useState, useEffect, createContext } from "react";
import Axios from "axios";
import { makeStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import CardActions from "@material-ui/core/CardActions";
import CardContent from "@material-ui/core/CardContent";
import Container from "@material-ui/core/Container";
import Divider from "@material-ui/core/Divider";
import Grid from "@material-ui/core/Grid";
import ListItemText from "@material-ui/core/ListItemText";
import Paper from "@material-ui/core/Paper";
import Typography from "@material-ui/core/Typography";
// import style
const useStyles = makeStyles({
root: {
minWidth: 275,
},
title: {
fontSize: 14,
},
pos: {
marginBottom: 12,
},
});
export const TestContext = createContext(5000);
function User() {
const classes = useStyles();
/* get all users */
const [allUsers, setAllUsers] = useState([{}]);
const getAllUsers = () => {
const url = `http://localhost:5000/api/users`;
Axios.get(url)
.then((response) => response.data)
.then((data) => setAllUsers(data));
};
useEffect(() => {
return getAllUsers();
}, []);
/* get one user */
const [user, setUser] = useState([{}]);
const getOneUser = (userId) => {
const url = `http://localhost:5000/api/users/${userId}`;
Axios.get(url)
.then((response) => response.data)
.then((data) => setUser(data));
};
useEffect(() => {
getOneUser();
}, [allUsers]);
/* init energy */
const [energyConsuption, setEnergyConsuption] = useState({});
const calcDailyEnergyConsumption = () => {
// for a male
const basalMetabolicRate =
1.083 *
Math.pow(weight, 0.48) *
Math.pow(height, 0.5) *
Math.pow(age, -0.13) *
191;
const dailyEnergyConsumption = basalMetabolicRate * activity;
return setEnergyConsuption({
mb_rate: basalMetabolicRate.toFixed(2),
daily_energy: dailyEnergyConsumption.toFixed(2),
});
};
useEffect(() => {
calcDailyEnergyConsumption();
}, [user]);
/* init Proteins, Lipids, Glucids state */
const [PLG, setPLG] = useState({});
/* init info needed by user */
const weight = user.weight;
const height = user.height;
const age = user.age;
const activity = 1.4;
/* calculate proteins / lipids / glucids ratio */
const calcLipGlucProt = () => {
// DEC means Daily Energy Consuption
let DEC = energyConsuption.daily_energy;
const proteins = user.weight * 1.8;
DEC = DEC - proteins * 4;
const lipids = user.weight * 1;
DEC = DEC - lipids * 9;
const glucids = DEC / 4;
return setPLG({
proteins: proteins.toFixed(2),
lipids: lipids.toFixed(2),
glucids: glucids.toFixed(2),
});
};
useEffect(() => {
calcLipGlucProt();
}, [energyConsuption]);
return (
<Container>
<h1>{energyConsuption.daily_energy}</h1>
<TestContext.Provider value="2000">
<Grid container spacing={1}>
{allUsers.map((userDetail) => (
<Grid item xs={2}>
<Paper>
<Button
onClick={() => getOneUser(userDetail.id)}
>
{userDetail.id} {userDetail.firstname}
</Button>
</Paper>
</Grid>
))}
</Grid>
<Card className={classes.root}>
<CardContent>
<Typography
variant="h5"
component="h2"
gutterBottom
>{`Bonjour ${user.firstname} ${user.lastname}`}</Typography>
<Divider />
<Typography
className={classes.pos}
color="textSecondary"
>
age : {user.age} ans
</Typography>
<Typography
className={classes.pos}
color="textSecondary"
>
taille : {user.height} m
</Typography>
<Typography
className={classes.pos}
color="textSecondary"
>
poid : {user.weight} kg
</Typography>
<Typography
className={classes.pos}
color="textSecondary"
>
activité : {user.id_activity} (sédentaire)
</Typography>
<Typography
className={classes.pos}
color="textSecondary"
>
objectif : {user.id_goal}(perdre du poid)
</Typography>
<Divider />
<Typography display="block" paragraph gutterBottom>
Votre <u>métabolisme basal</u> est de
<strong>
{" "}
{energyConsuption.mb_rate} calories
</strong>{" "}
et votre <u>dépense énergétique journalière</u> est
de
<strong>
{energyConsuption.daily_energy} calories
</strong>
</Typography>
<Typography display="block">
Vous devez consommer idéalement
<ListItemText href="#simple-list">
- {PLG.proteins} grammes de protéines
</ListItemText>
<ListItemText href="#simple-list">
- {PLG.lipids} grammes de lipides
</ListItemText>
<ListItemText href="#simple-list">
- {PLG.glucids} grammes de glucides
</ListItemText>
</Typography>
<Divider />
<Typography
variant="caption"
display="block"
gutterBottom
>
Ces informations ne remplace en aucun cas l'avis
médical d'un expert.
</Typography>
</CardContent>
<CardActions>
<Button size="small">Mettre à jour mes infos</Button>
</CardActions>
</Card>
</TestContext.Provider>
</Container>
);
}
export default User;
子组件
import React, { useState, useEffect, useContext } from "react";
import { TestContext } from "../Users/Users";
import Axios from "axios";
import Container from "@material-ui/core/Container";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import Card from "@material-ui/core/Card";
import CardActions from "@material-ui/core/CardActions";
import CardContent from "@material-ui/core/CardContent";
import Button from "@material-ui/core/Button";
import TextField from "@material-ui/core/TextField";
import Paper from "@material-ui/core/Paper";
function Recipes() {
const value = useContext(TestContext);
// console.log("Context", TestContext);
const [allFoods, setAllFoods] = useState([{}]);
const [food, setFood] = useState([{}]);
const [foodQuantity, setFoodQuantity] = useState(0);
const getAllFoods = () => {
const url = "http://localhost:5000/api/foods";
Axios.get(url)
.then((response) => response.data)
.then((data) => setAllFoods(data));
};
useEffect(() => {
return getAllFoods();
}, []);
const getOneFood = (foodId) => {
const url = `http://localhost:5000/api/foods/${foodId}`;
Axios.get(url)
.then((response) => response.data)
.then((data) => setFood(data));
};
useEffect(() => {
getOneFood();
}, [allFoods]);
const getFoodName = allFoods.map((foodDetail) => (
<Button onClick={() => getOneFood(foodDetail.id)}>
<Paper>{foodDetail.name}</Paper>
</Button>
));
const calcFoodQuantity = () => {
const total = 100 * (calories / food.calories);
setFoodQuantity(total.toFixed(2));
};
return (
<Container>
<Card>
<Grid container spacing={1}>
{getFoodName}
</Grid>
<Typography variant="h2" gutterBottom>
Calculer une recette pour {value} calories
</Typography>
<CardContent>
<Typography>{food.name}</Typography>
<Typography>{food.calories} cals</Typography>
</CardContent>
<CardActions>
<Button
size="small"
color="secondary"
onClick={() => calcFoodQuantity()}
>
Calculer
</Button>
<Typography>
il vous faut {foodQuantity} grammes de {food.name} pour
atteindre votre dépense énergétique journalière
</Typography>
</CardActions>
</Card>
</Container>
);
}
export default Recipes;
提前感谢您的帮助
来自文档的 Provider
:
https://reactjs.org/docs/context.html#contextprovider
Accepts a value prop to be passed to consuming components that are descendants of this Provider
您的 Provider 位于 User
组件的顶部,这意味着提供程序内的所有组件都获取上下文值。您的 Recipes
组件不是该树的一部分,而是 App
组件本身。
您可能需要将 Provider 添加到 'App' 的顶部或相应地重新构建您的组件。
例如,这将解决您的问题,因为 Recipes
是层次结构的一部分。
function App() {
return (
<Container>
<TestContext.Provider value="TEST"> // My wealth for my family under me
<Users /> //Users and all child components get them
<Menu /> // Me too. my family tree gets context
<Switch>
<Route exact path="/" />
<Route path="/aliments" component={Foods} /> // Me too. my family gets context
<Route path="/recettes" component={Recipes} /> // Me too. my family gets context
<Route path="/repas" component={Meals} /> // Me too. my family gets context
<Route path="/planning" component={Planning} /> // Me too. my family gets too
</Switch>
</TestContext.Provider>
</Container>
);
}
我正在尝试使用 useContext() 但 Provider 不传递该值,即使我使用像这样的假值也是如此:
<TestContext.Provider value="2000">
并保留初始化上下文的默认值:
export const TestContext = createContext(5000);
所以有代码:
父组件
import React, { useState, useEffect, createContext } from "react";
import Axios from "axios";
import { makeStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import Card from "@material-ui/core/Card";
import CardActions from "@material-ui/core/CardActions";
import CardContent from "@material-ui/core/CardContent";
import Container from "@material-ui/core/Container";
import Divider from "@material-ui/core/Divider";
import Grid from "@material-ui/core/Grid";
import ListItemText from "@material-ui/core/ListItemText";
import Paper from "@material-ui/core/Paper";
import Typography from "@material-ui/core/Typography";
// import style
const useStyles = makeStyles({
root: {
minWidth: 275,
},
title: {
fontSize: 14,
},
pos: {
marginBottom: 12,
},
});
export const TestContext = createContext(5000);
function User() {
const classes = useStyles();
/* get all users */
const [allUsers, setAllUsers] = useState([{}]);
const getAllUsers = () => {
const url = `http://localhost:5000/api/users`;
Axios.get(url)
.then((response) => response.data)
.then((data) => setAllUsers(data));
};
useEffect(() => {
return getAllUsers();
}, []);
/* get one user */
const [user, setUser] = useState([{}]);
const getOneUser = (userId) => {
const url = `http://localhost:5000/api/users/${userId}`;
Axios.get(url)
.then((response) => response.data)
.then((data) => setUser(data));
};
useEffect(() => {
getOneUser();
}, [allUsers]);
/* init energy */
const [energyConsuption, setEnergyConsuption] = useState({});
const calcDailyEnergyConsumption = () => {
// for a male
const basalMetabolicRate =
1.083 *
Math.pow(weight, 0.48) *
Math.pow(height, 0.5) *
Math.pow(age, -0.13) *
191;
const dailyEnergyConsumption = basalMetabolicRate * activity;
return setEnergyConsuption({
mb_rate: basalMetabolicRate.toFixed(2),
daily_energy: dailyEnergyConsumption.toFixed(2),
});
};
useEffect(() => {
calcDailyEnergyConsumption();
}, [user]);
/* init Proteins, Lipids, Glucids state */
const [PLG, setPLG] = useState({});
/* init info needed by user */
const weight = user.weight;
const height = user.height;
const age = user.age;
const activity = 1.4;
/* calculate proteins / lipids / glucids ratio */
const calcLipGlucProt = () => {
// DEC means Daily Energy Consuption
let DEC = energyConsuption.daily_energy;
const proteins = user.weight * 1.8;
DEC = DEC - proteins * 4;
const lipids = user.weight * 1;
DEC = DEC - lipids * 9;
const glucids = DEC / 4;
return setPLG({
proteins: proteins.toFixed(2),
lipids: lipids.toFixed(2),
glucids: glucids.toFixed(2),
});
};
useEffect(() => {
calcLipGlucProt();
}, [energyConsuption]);
return (
<Container>
<h1>{energyConsuption.daily_energy}</h1>
<TestContext.Provider value="2000">
<Grid container spacing={1}>
{allUsers.map((userDetail) => (
<Grid item xs={2}>
<Paper>
<Button
onClick={() => getOneUser(userDetail.id)}
>
{userDetail.id} {userDetail.firstname}
</Button>
</Paper>
</Grid>
))}
</Grid>
<Card className={classes.root}>
<CardContent>
<Typography
variant="h5"
component="h2"
gutterBottom
>{`Bonjour ${user.firstname} ${user.lastname}`}</Typography>
<Divider />
<Typography
className={classes.pos}
color="textSecondary"
>
age : {user.age} ans
</Typography>
<Typography
className={classes.pos}
color="textSecondary"
>
taille : {user.height} m
</Typography>
<Typography
className={classes.pos}
color="textSecondary"
>
poid : {user.weight} kg
</Typography>
<Typography
className={classes.pos}
color="textSecondary"
>
activité : {user.id_activity} (sédentaire)
</Typography>
<Typography
className={classes.pos}
color="textSecondary"
>
objectif : {user.id_goal}(perdre du poid)
</Typography>
<Divider />
<Typography display="block" paragraph gutterBottom>
Votre <u>métabolisme basal</u> est de
<strong>
{" "}
{energyConsuption.mb_rate} calories
</strong>{" "}
et votre <u>dépense énergétique journalière</u> est
de
<strong>
{energyConsuption.daily_energy} calories
</strong>
</Typography>
<Typography display="block">
Vous devez consommer idéalement
<ListItemText href="#simple-list">
- {PLG.proteins} grammes de protéines
</ListItemText>
<ListItemText href="#simple-list">
- {PLG.lipids} grammes de lipides
</ListItemText>
<ListItemText href="#simple-list">
- {PLG.glucids} grammes de glucides
</ListItemText>
</Typography>
<Divider />
<Typography
variant="caption"
display="block"
gutterBottom
>
Ces informations ne remplace en aucun cas l'avis
médical d'un expert.
</Typography>
</CardContent>
<CardActions>
<Button size="small">Mettre à jour mes infos</Button>
</CardActions>
</Card>
</TestContext.Provider>
</Container>
);
}
export default User;
子组件
import React, { useState, useEffect, useContext } from "react";
import { TestContext } from "../Users/Users";
import Axios from "axios";
import Container from "@material-ui/core/Container";
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import Card from "@material-ui/core/Card";
import CardActions from "@material-ui/core/CardActions";
import CardContent from "@material-ui/core/CardContent";
import Button from "@material-ui/core/Button";
import TextField from "@material-ui/core/TextField";
import Paper from "@material-ui/core/Paper";
function Recipes() {
const value = useContext(TestContext);
// console.log("Context", TestContext);
const [allFoods, setAllFoods] = useState([{}]);
const [food, setFood] = useState([{}]);
const [foodQuantity, setFoodQuantity] = useState(0);
const getAllFoods = () => {
const url = "http://localhost:5000/api/foods";
Axios.get(url)
.then((response) => response.data)
.then((data) => setAllFoods(data));
};
useEffect(() => {
return getAllFoods();
}, []);
const getOneFood = (foodId) => {
const url = `http://localhost:5000/api/foods/${foodId}`;
Axios.get(url)
.then((response) => response.data)
.then((data) => setFood(data));
};
useEffect(() => {
getOneFood();
}, [allFoods]);
const getFoodName = allFoods.map((foodDetail) => (
<Button onClick={() => getOneFood(foodDetail.id)}>
<Paper>{foodDetail.name}</Paper>
</Button>
));
const calcFoodQuantity = () => {
const total = 100 * (calories / food.calories);
setFoodQuantity(total.toFixed(2));
};
return (
<Container>
<Card>
<Grid container spacing={1}>
{getFoodName}
</Grid>
<Typography variant="h2" gutterBottom>
Calculer une recette pour {value} calories
</Typography>
<CardContent>
<Typography>{food.name}</Typography>
<Typography>{food.calories} cals</Typography>
</CardContent>
<CardActions>
<Button
size="small"
color="secondary"
onClick={() => calcFoodQuantity()}
>
Calculer
</Button>
<Typography>
il vous faut {foodQuantity} grammes de {food.name} pour
atteindre votre dépense énergétique journalière
</Typography>
</CardActions>
</Card>
</Container>
);
}
export default Recipes;
提前感谢您的帮助
来自文档的 Provider
:
https://reactjs.org/docs/context.html#contextprovider
Accepts a value prop to be passed to consuming components that are descendants of this Provider
您的 Provider 位于 User
组件的顶部,这意味着提供程序内的所有组件都获取上下文值。您的 Recipes
组件不是该树的一部分,而是 App
组件本身。
您可能需要将 Provider 添加到 'App' 的顶部或相应地重新构建您的组件。
例如,这将解决您的问题,因为 Recipes
是层次结构的一部分。
function App() {
return (
<Container>
<TestContext.Provider value="TEST"> // My wealth for my family under me
<Users /> //Users and all child components get them
<Menu /> // Me too. my family tree gets context
<Switch>
<Route exact path="/" />
<Route path="/aliments" component={Foods} /> // Me too. my family gets context
<Route path="/recettes" component={Recipes} /> // Me too. my family gets context
<Route path="/repas" component={Meals} /> // Me too. my family gets context
<Route path="/planning" component={Planning} /> // Me too. my family gets too
</Switch>
</TestContext.Provider>
</Container>
);
}