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;

提前感谢您的帮助

来自文档的 Providerhttps://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>
  );
}