【发布时间】: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