为了尝试使用 React hooks,我用这个组件给自己挖了一个很深的兔子洞。
父组件处理最终分发到多个组件的字典
状态。
我的问题子组件 WordInput
有一个带有单个输入的表单。提交表单时,组件从 API 获取单词的定义,并将单词和定义传递给父级,然后父级以字典的形式设置状态。到目前为止,如果它是字典中的第一个单词,那就太好了。我遇到麻烦的部分是提交任何后续单词/定义。
当用户提交后续单词时,我希望组件检查该单词是否已存在于传递给子项的字典
中。如果不存在,请通过提交功能将其添加到字典
中。
我认为问题是我试图用 useEffect
做太多事情
我 useEffect
来:
- 设置加载
- 检查并处理字典中现有的单词
- 检查定义和单词是否不为空并将两者提交给父/词典
- 从 API 获取定义
在未处理的代码中,我有多个 console.groups
来帮助我跟踪正在发生的情况。添加到组件中的越多,子组和子组的子组就越多。显然,我采用的方法不是很干燥,并且会导致组件/useEffect 函数的过多重新渲染。为了简洁起见,我删除了 console.log
条目。
导入的fetchWordDefinition
仅处理获取的数据并将其正确排列到数组中。
我不知道如何保持干燥和有效,对于这个相当简单的任务,我们将不胜感激。我的直觉是保留提交处理程序中提交单词/定义的所有逻辑,并且仅使用 useEffect
来验证之前的数据。
import React, { useState, useEffect } from "react";
import fetchWordDefinition from "./lib/utils";
const WordInput = ({ onSubmit, dictionary }) => {
const [definition, setDefinition] = useState([]);
const [cause, setCause] = useState({ function: "" });
const [error, setError] = useState({});
const [loading, setLoading] = useState(false);
const [word, setWord] = useState("");
const [wordExistsInDB, setWordExistsInDB] = useState(false);
useEffect(() => {
const dictionaryEmpty = dictionary.length === 0 ? true : false;
if (dictionaryEmpty) {
return;
} else {
for (let i = 0; i < dictionary.length; i += 1) {
if (dictionary[i].word === word) {
setWordExistsInDB(true);
setError({ bool: true, msg: "Word already exists in DB" });
break;
} else {
setWordExistsInDB(false);
setError({ bool: false, msg: "" });
}
}
}
}, [dictionary, word]);
useEffect(() => {
const definitionNotEmpty = definition.length !== 0 ? true : false;
const wordNotEmpty = word !== "" ? true : false;
if (wordNotEmpty && definitionNotEmpty && !wordExistsInDB) {
onSubmit(word, definition);
setWord("");
setDefinition([]);
}
}, [definition, word, onSubmit, wordExistsInDB]);
useEffect(() => {
if (cause.function === "fetch") {
async function fetchFunction() {
const fetch = await fetchWordDefinition(word);
return fetch;
}
fetchFunction().then(definitionArray => {
setDefinition(definitionArray);
setCause({ function: "" });
});
}
}, [cause, word]);
const handleSubmit = async e => {
e.preventDefault();
setLoading(true);
setCause({ function: "fetch" });
};
return (
<form onSubmit={handleSubmit}>
{error.bool ? <span>{error.msg}</span> : null}
<input
name='word'
placeholder='Enter Word'
type='text'
value={word}
onChange={({ target: { value } }) => setWord(value)}
/>
<input type='submit' />
</form>
);
};
export default WordInput;
最佳答案
确实发生了不必要的 useEffect
事件以及大部分状态。您所需要的只是 handleSubmit
来进行提取。
const WordInput = ({ onSubmit, dictionary }) => {
const [word, setWord] = React.useState("");
const handleChange = React.useCallback(e => {
setWord(e.currentTarget.value)
}, [])
const handleSubmit = React.useCallback(() => {
//check if word is in dictionary
const wordIsAlreadyThere = dictionary.map(entry => entry.word).includes(word)
//fetch the definition, wait for it, and call submit
if(!wordIsAlreadyThere && word.length > 0){
fetchWordDefinition(word)
.then(definition => {
onSubmit(word, definition)
setWord('')
}).catch(err => console.log(err))
}
}, [])
return (
<form onSubmit={handleSubmit}>
<input
value={word}
onChange={handleChange}/>
<input type='submit' />
</form>
);
}
关于javascript - 具有提升状态和受控依赖的 React 表单提交逻辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60311586/