【问题标题】:tag:ReactJS Context.Provider value is not updated标签:ReactJS Context.Provider 值没有更新
【发布时间】:2020-11-15 03:11:58
【问题描述】:

我正在尝试 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;

提前感谢您的帮助

【问题讨论】:

  • ps:父子组件不在同一层树上。上下文正在与其他组件(如 )上的基本方式一起使用
  • 我看到您的React 版本是16.13.1。也许,您应该将其更新为 16.8 +

标签: reactjs react-hooks provider


【解决方案1】:

来自文档的Providerhttps://reactjs.org/docs/context.html#contextprovider

接受要传递给作为此 Provider 后代的消费组件的 value 属性

您的 Provider 位于 User 组件的顶部,这意味着 Provider 内的所有组件都获取上下文值。您的 Recipes 组件不是该树的一部分,而是 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>
  );
}

【讨论】:

  • 好的,我明白了!我想将我的提供者保持在用户的顶层,但我需要在 Users.jsx 上导入食谱。它现在工作正常,我只需要重新组织路由器。我将组件层次结构与树结构混淆了!谢谢
  • 是的,但只有分支专长/食谱,而不是开发。我现在必须修好路线,非常感谢!
  • 开发是最新的 ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-05
  • 2016-01-16
相关资源
最近更新 更多