Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/458.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React钩子:为什么useEffect需要一个详尽的依赖关系数组?_Javascript_Reactjs_Typescript_React Hooks - Fatal编程技术网

Javascript React钩子:为什么useEffect需要一个详尽的依赖关系数组?

Javascript React钩子:为什么useEffect需要一个详尽的依赖关系数组?,javascript,reactjs,typescript,react-hooks,Javascript,Reactjs,Typescript,React Hooks,我在React组件中有以下用例 它是一个使用的搜索用户输入。它的值总是一个ID,所以我只有用户ID作为道具。因此,在第一次加载时,为了显示用户名值,我需要在第一次装载时获取它 编辑:我不想在以后更改时再次获取该值,因为我已经从建议请求中获取了该值 type InputUserProps = { userID?: string; onChange: (userID: string) => void; }; // Input User is a controlled input co

我在React组件中有以下用例

它是一个使用的搜索用户输入。它的值总是一个ID,所以我只有用户ID作为道具。因此,在第一次加载时,为了显示用户名值,我需要在第一次装载时获取它

编辑:我不想在以后更改时再次获取该值,因为我已经从建议请求中获取了该值

type InputUserProps = {
  userID?: string;
  onChange: (userID: string) => void;
};

// Input User is a controlled input
const InputUser: React.FC<InputUserProps> = (props) => {
  const [username, setUsername] = useState<string | null>(null);

  useEffect(() => {
    if (props.userID && !username) {
      fetchUsername(props.userID).then((username) => setUsername(username));
    }
  }, []);

  async function loadSuggestions(inputValue: string): Suggestion[] {
    return fetchSuggestions(inputValue);
  }

  function selectSuggestion(suggestion: Suggestion): void {
    props.onChange(suggestion.userID); // I don't want to rerun the effect from that change...
    setUsername(suggestion.username); // ...because I set the username here
  }

  return (
    <InputSuggest
      value={props.userID}
      label={username}
      onSuggestionsRequested={loadSuggestions}
      onSuggestionSelected={selectSuggestion}
    />
  );
};

export default InputUser;
但是如果我这样做,我将不止一次地运行它,因为钩子本身更改了用户名值!由于它在没有所有依赖项的情况下工作,我想知道:

  • 我怎样才能干净利落地解决我的案子
  • 这些依赖关系是什么?为什么建议对它们进行详尽的描述

如果您确定在安装InputUser组件之前,所有依赖的道具都已填充并且具有正确的值,则在
}之前添加
eslint禁用下一行react hooks/deps
,[])
行,但如果依赖的道具在第一次安装组件时没有值,因此,您必须将它们添加到useEffect依赖项中。

看起来用户ID确实应该是一个依赖项,因为如果它发生变化,您需要再次运行查询

我认为您可以取消对
用户名的检查,并始终在
用户名更改时提取,并且仅在
用户名更改时提取:

useEffect(() => {
    if(props.userID) {
        fetchUsername(props.userID)
            .then((username) => setUsername(username))
    }
}, [props.userID])
一般来说,您希望列出效果中的所有闭包变量,以避免在执行效果时出现过时的引用

--编辑以解决OP问题: 因为在您的用例中,您知道您只希望在传递空依赖项数组的初始装载上执行操作是一种有效的方法

另一个选项是跟踪获取的用户ID,例如

const fetchedIds = useRef(new Set())
无论何时获取新ID的用户名,都可以更新ref:

fetchedIds.current.add(newId)
在您的效果中,您可以测试:

if (props.userID && !fetchedIds.current.has(props.userID)) {
   // do the fetch
}
这些部门是什么

useffect
接受可选的第二个参数,该参数是一个依赖项数组。
useffect
hook的依赖项告诉它在依赖项发生变化时运行效果

如果您没有将可选的第二个参数传递给useEffect钩子,它将在每次组件重新呈现时执行。空依存关系数组指定在组件的初始渲染之后,只运行一次效果。在这种情况下,
useffect
hook的行为几乎类似于类组件中的componentDidMount

为什么建议对其进行详尽说明

效果请参见中定义的渲染中的
道具
状态
。因此,当您在
useffect
hook的回调函数中使用参与react数据流的功能组件范围内的某些内容(如props或state)时,该回调函数将关闭该数据,除非使用props和state的新值定义新效果,您的效果将看到过时的道具和状态值

下面的代码片段演示了如果您对
useffect
hook的依赖关系撒谎,可能会出现什么问题

在下面的代码片段中,有两个组件,
App
User
<代码>应用程序
组件有三个按钮,并维护由
用户
组件显示的用户id。用户id作为道具从
App
传递到
User
组件,
User
组件从
jsonplaceholder
API获取id作为道具传递的用户

现在,下面代码段中的问题是它不能正常工作。原因在于它与
useffect
hook的依赖性有关
useffect
hook依赖于
userID
prop从API获取用户,但由于我跳过了将
userID
添加为依赖项,因此
useffect
hook不会每次
userID
prop更改时都执行

函数用户({userID}){
const[user,setUser]=React.useState(null);
React.useffect(()=>{
如果(用户ID>0){
取回(`https://jsonplaceholder.typicode.com/users/${userID}`)
.then(response=>response.json())
.然后(用户=>setUser(用户))
.catch(error=>console.log(error.message));
}
}, []); 
返回(
{user?{user.name}:没有要显示的用户

} ); } 函数App(){ const[userID,setUserID]=React.useState(0); 常量handleClick=(id)=>{ setUserID(id); }; 返回( handleClick(1)}>ID为1的用户 handleClick(2)}>ID为2的用户 handleClick(3)}>ID为3的用户 当前用户ID:{userID}


); } ReactDOM.render(,document.getElementById('root'))


是的,我会这么做的。但是从eslint react规则集得到的警告告诉我这有问题。我甚至在运行eslint时自动修复--修复!请注意,我删除了对
用户名的依赖关系
-在我的回答中使用该代码会出现什么错误?没错,我没有收到任何错误。但是,当我选择一个建议时,它将触发onChange,设置一个新的props.userID并再次获取用户名(我已经从建议请求中获取了该用户名)。我刚刚用一个更详尽的例子编辑了我的文章,很抱歉之前没有这么做;-)请添加更改
用户ID
的代码,我不确定我/我在跟踪您该用户ID是受控输入,因此它需要一个值和一个onChange回调。我将编辑我的帖子,因为规则是由react核心团队编写的,所以我的观点是,如果它大叫,我的设计可能有问题。这更是我问题的重点;-)我不想重新运行更改后的效果-如果我理解您更新的问题,您希望效果只运行一次,因此使用空数组是可以的。或者,您可以包括
fetchedIds.current.add(newId)
if (props.userID && !fetchedIds.current.has(props.userID)) {
   // do the fetch
}