【问题标题】:Child > Parent > Child props not appearing on first renderChild > Parent > Child 道具未出现在第一次渲染时
【发布时间】:2020-08-18 17:45:59
【问题描述】:

我正在构建一个搜索营养 api 并返回卡路里等的应用程序。作为其中的一部分,我正在添加一个功能,用户可以在其中设置每日卡路里量和宏观分解(蛋白质、碳水化合物、脂肪百分比)。

当用户输入他们的百分比并点击计算时,它会将道具从子级 (MacroSelector) 传递给父级 (App),用于计算所需的蛋白质/脂肪/碳水化合物的克数并将其传递给 FoodTable。

但是,它不会在第一次单击计算按钮时执行此操作。相反,我需要单击“计算”两次以将宏传递给孩子。任何帮助表示赞赏。

在 MacroSelector 中,用户在输入中输入他们想要的蛋白质、碳水化合物和脂肪的百分比。然后将其作为 props 传递给 macroHandler 中的父组件。

const MacroSelector = (props) => {
  const [protein, setProtein] = useState();
  const [carbs, setCarbs] = useState();
  const [fat, setFat] = useState();

  const proteinHandler = (e) => {
    setProtein(e);
  };

  const carbsHandler = (e) => {
    setCarbs(e);
  };

  const fatHandler = (e) => {
    setFat(e);
  };

  const macrosHandler = () => {
    props.macrosHandler({ protein, carbs, fat });
  };

  return (
    <div>
      <Form
        style={{
          display: "grid",
          gridTemplateColumns: "repeat(24, 1fr)",
        }}
      >
        <div
          style={{
            gridColumn: "1/2",
            lineHeight: "1.8",
            marginLeft: "10px",
            marginRight: "10px",
          }}
        >
          Protein{" "}
        </div>
        <Input
          style={{ gridColumn: "2/4", marginRight: "10px" }}
          type="number"
          name="protein"
          onChange={(e) => proteinHandler(e.target.value)}
        />
        <div
          style={{
            gridColumn: "5/6",
            lineHeight: "1.8",
            marginRight: "10px",
          }}
        >
          Carbs{" "}
        </div>
        <Input
          style={{ gridColumn: "6/8", marginRight: "10px" }}
          type="number"
          name="carbs"
          onChange={(e) => carbsHandler(e.target.value)}
        />
        <div
          style={{
            gridColumn: "9/10",
            lineHeight: "1.8",
            marginRight: "10px",
          }}
        >
          Fat{" "}
        </div>
        <Input
          style={{ gridColumn: "10/12" }}
          type="number"
          name="fat"
          onChange={(e) => fatHandler(e.target.value)}
        />

        <Button
          style={{ gridColumn: "14/18" }}
          name="approve"
          onClick={macrosHandler}
        >
          Calculate
        </Button>
      </Form>
    </div>
  );
};

export default MacroSelector;

在 App 组件中,函数 macrosHandler 将从 MacroSelector 组件传递过来的 props 设置为 state(setDailyMacroBreakDown)。接下来,我们获取用户设置的卡路里,以及他们希望饮食中蛋白质、脂肪、碳水化合物的百分比,并计算出每种卡路里的克数。然后我们使用 setRemainingMacros 将其设置为状态。

然后我们将剩余宏作为道具传递给 FoodTable 组件 (remainingMacros = {remainingMacros})。 道具正在传递,但不是在最初单击“计算”按钮时传递,我不确定为什么。

如果用户输入 40 40 20,在第一次点击计算时,传递的 props 是 App 中剩余宏的默认状态。第二次点击计算,则传递40 40 20的道具。

感谢任何建议!

const App = (props) => {
  const [dailyCalorieSelector, setDailyCalorieSelector] = useState(1800);

  const [foodItemDetails, setFoodItemDetails] = useState([]);

  const [sumOfFoodItems, setSumOfFoodItems] = useState({
    protein: 0,
    carbs: 0,
    calories: 0,
    fat: 0,
  });

  // const [caloriesForMacros, setCaloriesForMacros] = useState();

  const [remainingMacros, setRemainingMacros] = useState({
    protein: 0,
    fat: 0,
    carbs: 0,
  });

  const [dailyMacroBreakdown, setDailyMacroBreakdown] = useState({
    protein: 0,
    carbs: 0,
    fat: 0,
  });

  const removeRow = (props) => {
    let deletedRowNewArray = foodItemDetails.filter((row) => {
      return row.id !== props.id;
    });
    setFoodItemDetails(deletedRowNewArray);

    setSumOfFoodItems({
      fat: sumOfFoodItems.fat - props.fat,
      protein: sumOfFoodItems.protein - props.protein,
      carbs: sumOfFoodItems.carbs - props.carbs,
      calories: sumOfFoodItems.calories - props.calories,
    });
  };

  const macrosHandler = (props) => {
    setDailyMacroBreakdown(props);
    const proteinCalories =
      (dailyCalorieSelector * (dailyMacroBreakdown.protein / 100)) / 4;
    const carbsCalories =
      (dailyCalorieSelector * (dailyMacroBreakdown.carbs / 100)) / 4;
    const fatCalories =
      (dailyCalorieSelector * (dailyMacroBreakdown.fat / 100)) / 9;

    setRemainingMacros({
      protein: proteinCalories,
      carbs: carbsCalories,
      fat: fatCalories,
    });

    console.log("remaining", remainingMacros);
    // setCaloriesForMacros(dailyCalorieSelector);
  };

  const setCalorieHandler = (e) => {
    setDailyCalorieSelector(e.target.value);
  };

  const onSearchSubmit = async (props) => {
    let data = { title: props, ingr: [props] }; //ingr = ingredients list + title required
    await axios
      .post(
        `https://api.edamam.com/api/nutrition-details?app_id=8b84adef&app_key=a931603d6a495dba409096cbf9eb7f71`,
        data
      )
      .then((response) => {
        setFoodItemDetails([
          ...foodItemDetails,
          {
            name: props,
            id: uuidv4(),
            fat: response.data.totalNutrients.FAT.quantity.toFixed(),
            protein: response.data.totalNutrients.PROCNT.quantity.toFixed(),
            carbs: response.data.totalNutrients.CHOCDF.quantity.toFixed(),
            calories: response.data.calories,
          },
        ]);

        setSumOfFoodItems({
          fat:
            sumOfFoodItems.fat +
            parseInt(response.data.totalNutrients.FAT.quantity.toFixed()),
          protein:
            sumOfFoodItems.protein +
            parseInt(response.data.totalNutrients.PROCNT.quantity.toFixed()),
          carbs:
            sumOfFoodItems.carbs +
            parseInt(response.data.totalNutrients.CHOCDF.quantity.toFixed()),
          calories: sumOfFoodItems.calories + response.data.calories,
        });
        // console.log("sumoffood", sumOfFoodItems);
      })
      .catch((err) => {
        console.log(err);
      });
  };
  return (
    <div className="Card">
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "repeat(12, 1fr)",
          margin: "25px 0px",
        }}
      >
        <div style={{ gridColumn: "3/11" }}>
          <Chart />
        </div>
      </div>

      <div>
        <div style={{ width: "50%" }}>
          {dailyMacroBreakdown && (
            <div>
              {" "}
              {`Protein: ${dailyMacroBreakdown.protein}, Carbs: ${dailyMacroBreakdown.carbs}, Fat: ${dailyMacroBreakdown.fat}`}{" "}
            </div>
          )}
        </div>

        <div style={{ width: "50%" }}>
          <Form>
            <Label for="volume">
              {`Select Daily Calorie Intake: ${dailyCalorieSelector}`}
            </Label>

            <Input
              type="range"
              id="volume"
              name="volume"
              min="800"
              max="6000"
              step="10"
              value={dailyCalorieSelector}
              onChange={setCalorieHandler}
            />
          </Form>
        </div>
        <MacroSelector macrosHandler={macrosHandler} />
        <div
          style={{
            display: "grid",
            gridTemplateColumns: "repeat(12, 1fr)",
            margin: "25px 0px",
          }}
        >
          <div style={{ gridColumn: "2/11" }}>
            <Searcher onSearchSubmit={onSearchSubmit} />
          </div>
        </div>

        <FoodTable
          foodItemDetails={foodItemDetails}
          sumOfFoodItems={sumOfFoodItems}
          removeRow={removeRow}
          dailyCalorieSelector={dailyCalorieSelector}
          remainingMacros={remainingMacros}
        />
      </div>
    </div>
  );
};

export default App;

在第一次点击计算时没有收到道具的子组件如下。

const FoodTable = (props) => {
  const { foodItemDetails, sumOfFoodItems } = props;
  const { fat, protein, carbs, calories } = sumOfFoodItems;

  console.log("sumOfFoodItems ", props);

  const removeRow = (e) => {
    props.removeRow(e);
  };

  return (
    <div>
      <Table striped>
        <thead>
          <tr>
            <th>#</th>
            <th>Food & Quantity</th>
            <th>Fat </th>
            <th>Carbs</th>
            <th>Protein</th>
            <th>Calories</th>
          </tr>
        </thead>

        <tbody>
          {foodItemDetails.length > 0 &&
            foodItemDetails.map((foodItem, index) => {
              return (
                <tr key={foodItem.id}>
                  <th scope="row">{index + 1}</th>
                  <td>{foodItem.name}</td>
                  <td>{foodItem.fat} g</td>
                  <td>{foodItem.carbs} g</td>
                  <td>{foodItem.protein} g</td>
                  <td>{foodItem.calories} kCal </td>
                  <td>
                    <BsFillPlusCircleFill
                      onClick={() => removeRow(foodItem)}
                    ></BsFillPlusCircleFill>
                  </td>
                </tr>
              );
            })}
        </tbody>
        <tbody>
          <tr style={{ backgroundColor: "grey" }}>
            <th scope="row"></th>
            <td style={{ fontWeight: "bold" }}>Total</td>
            <td>{fat} g</td>
            <td>{carbs} g</td>
            <td>{protein} g</td>
            <td>{calories} kCal </td>
            <td> </td>
          </tr>
        </tbody>
        {props.remainingMacros && (
          <tfoot>
            <tr style={{ backgroundColor: "grey" }}>
              <th scope="row"></th>
              <td style={{ fontWeight: "bold" }}>Remaining</td>
              <td>{props.remainingMacros.fat - fat} g</td>
              <td>{props.remainingMacros.carbs - carbs} g</td>
              <td>{props.remainingMacros.protein - protein} g</td>
              <td>{props.dailyCalorieSelector - calories} kCal </td>
              <td> </td>
            </tr>
          </tfoot>
        )}
      </Table>
    </div>
  );
};
export default FoodTable;

【问题讨论】:

  • 我不清楚您的查询是什么。如果您可以改写查询,那就太好了。

标签: javascript reactjs


【解决方案1】:

问题在于您的App 组件,macrosHandler 函数。你设置了 state 并立即对这个 state 执行操作,但是你忘记了在 React 中设置 state 是异步的。所以,而不是这个:

const macrosHandler = (props) => {
    setDailyMacroBreakdown(props);
    //some operations on dailyMacroBreakdown that doesn't see the changed state
}

你可以试着听这样的变化:


const macrosHandler = (props) => {
    setDailyMacroBreakdown(props);
}

useEffect(() => {
    //some operations on dailyMacroBreakdown that DO see the updated state
}, [dailyMacroBreakdown]);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-12
    • 2016-03-22
    • 2021-12-04
    • 2019-10-14
    • 2013-07-30
    • 1970-01-01
    相关资源
    最近更新 更多