我正在构建一个 React 应用程序,它使用输入字段允许用户输入菜谱标题,然后,当他们提交表单时,菜谱应添加到 RecipeList 中。
目前,我的代码无法正常工作,因为在输入字段失去焦点之前我只能输入 1 个单词。如果我必须猜测,我会猜测当我输入字母时,表单会以某种方式重新呈现。 我想继续打字而不失去输入焦点。
这是我的代码:
function RecipeApp() {
const [recipes, setRecipes] = useState(initialRecipes);
const [recipeInput, setRecipeInput] = useState("");
const [summaryInput, setSummaryInput] = useState("");
const [ingredientsInput, setIngredientsInput] = useState([]);
const [cookTimeInput, setCookTimeInput] = useState("");
function handleAddRecipe(e) {
e.preventDefault();
if (!recipeInput || !summaryInput || !ingredientsInput || !cookTimeInput) {
alert("Please fill out all fields!");
return;
}
const newRecipe = {
id: recipes.length,
title: recipeInput,
summary: summaryInput,
ingredients: ingredientsInput.split(",").reduce(
(acc, ing, idx) => ({
...acc,
[`ingredient${idx + 1}`]: ing.trim(),
}),
{}
),
cookTime: parseInt(cookTimeInput, 10),
};
setRecipes([...recipes, newRecipe]);
setRecipeInput("");
setSummaryInput("");
setIngredientsInput("");
setCookTimeInput("");
}
function InputForm() {
return (
<form onSubmit={handleAddRecipe}>
<p>Recipe name</p>
<input
value={recipeInput}
onChange={(e) => setRecipeInput(e.target.value)}
/>
<p>Summary</p>
<input value={summaryInput} placeholder="Enter a description" />
<p>Ingredients</p>
<input
value={ingredientsInput}
placeholder="List up to four ingredients, seperated by a comma"
/>
<p>Cook Time (minutes)</p>
<input value={cookTimeInput} placeholder="Time in minutes" />
<button>Add</button>
</form>
);
}
function RecipeList() {
return (
<ul>
{recipes.map((recipe) => (
<li key={recipe.id}>
{recipe.title}
<button>View</button>
<button>Delete</button>
</li>
))}
</ul>
);
}
return (
<div className="RecipeApp">
<InputForm />
<h2>List of recipes:</h2>
<RecipeList />
</div>
);
}
原因:
InputForm 有输入,调用 setState 函数来更新值。 useState 会导致整个功能组件的重新渲染。这会导致您的代码重新渲染完整的 ReceipeApp,其中它返回带有 InputForm 和 ReceipeList 的 JSX。因此,在这里,InputForm 会使用任何输入中键入的每个字母的现有值(食谱、烹饪时间、收据列表等)重新呈现。
解决方案:
InputForm 函数必须位于 ReceipeApp 函数之外。尝试单独拥有每个功能,并在需要时传递 props。
示例:InputForm 可能如下所示
function InputForm() {
const [recipes, setRecipes] = useState([]);
const [recipeInput, setRecipeInput] = useState("");
const [summaryInput, setSummaryInput] = useState("");
const [ingredientsInput, setIngredientsInput] = useState([]);
const [cookTimeInput, setCookTimeInput] = useState("");
function handleAddRecipe(e) {
e.preventDefault();
if (!recipeInput || !summaryInput || !ingredientsInput || !cookTimeInput) {
alert("Please fill out all fields!");
return;
}
const newRecipe = {
id: recipes.length,
title: recipeInput,
summary: summaryInput,
ingredients: ingredientsInput.split(",").reduce(
(acc, ing, idx) => ({
...acc,
[`ingredient${idx + 1}`]: ing.trim(),
}),
{}
),
cookTime: parseInt(cookTimeInput, 10),
};
setRecipes([...recipes, newRecipe]);
setRecipeInput("");
setSummaryInput("");
setIngredientsInput("");
setCookTimeInput("");
}
return (
<form onSubmit={handleAddRecipe}>
<p>Recipe name</p>
<input
value={recipeInput}
onChange={(e) => {setRecipeInput(e.target.value)}}
/>
<p>Summary</p>
<input value={summaryInput} placeholder="Enter a description"
onChange={(e) => {setSummaryInput(e.target.value)}}/>
<p>Ingredients</p>
<input
value={ingredientsInput}
placeholder="List up to four ingredients, seperated by a comma"
onChange={(e) => {setIngredientsInput(e.target.value)}}
/>
<p>Cook Time (minutes)</p>
<input value={cookTimeInput} placeholder="Time in minutes"
onChange={(e) => {setCookTimeInput(e.target.value)}}/>
<button type='submit'>Add</button>
</form>
);
}
注意:将 type="submit" 添加到表单按钮并处理所有输入字段中的 onchange