我正在使用ReactHooks。我正在尝试访问ref
函数中User
组件的useEffect
。但是,尽管我将elRef.current
作为第二个参数传递给null
,但我得到的elRef.current
的值是useEffect
。但是我想参考div
元素。但是useEffect
的外部(函数体)的值ref
可用。这是为什么 ?如何获得elRef.current
中的useEffect
值?
代码
import React, { Component, useState, useRef, useEffect } from "react";
const useFetch = url => {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(
() => {
setIsLoading(true);
fetch(url)
.then(response => {
if (!response.ok) throw Error(response.statusText);
return response.json();
})
.then(json => {
setIsLoading(false);
setData(json.data);
})
.catch(error => {
setIsLoading(false);
setError(error);
});
},
[url]
);
return { data, isLoading, error };
};
const User = ({ id }) => {
const elRef = useRef(null);
const { data: user } = useFetch(`https://reqres.in/api/users/${id}`);
useEffect(() => {
console.log("ref", elRef.current);
}, [elRef.current]);
if (!user) return null;
return <div ref={elRef}>{user.first_name + " " + user.last_name}</div>;
};
class App extends Component {
state = {
userId: 1
};
handleNextClick = () => {
this.setState(prevState => ({
userId: prevState.userId + 1
}));
};
handlePrevNext = () => {
this.setState(prevState => ({
userId: prevState.userId - 1
}));
};
render() {
return (
<div>
<button
onClick={() => this.handlePrevClick()}
disabled={this.state.userId === 1}
>
Prevoius
</button>
<button onClick={() => this.handleNextClick()}>Next</button>
<User id={this.state.userId} />
</div>
);
}
}
export default App;
谢谢!
答案 0 :(得分:12)
您应该使用 useCallback 而不是reactjs docs中建议的useRef。
只要ref附加到其他节点,React都会调用该回调。
替换此:
df = pd.concat(dict_df).reset_index(level=1, drop=True).rename_axis('Dept').reset_index()
与此:
const elRef = useRef(null);
useEffect(() => {
console.log("ref", elRef.current);
}, [elRef.current]);
答案 1 :(得分:1)
这是可预见的行为。
正如提到的@estus
一样,您遇到了这个问题,因为第一次调用componentDidMount
时,您会得到null
(初始值),并且在下一个{{1} }更改,因为实际上引用仍然相同。
如果您需要考虑每个用户的更改,则应将elRef
作为第二个参数传递给函数,以确保在更改用户时触发[user]
。
Here是更新的沙箱。
希望有帮助。
答案 2 :(得分:0)
useEffect
可以替代componentDidMount
和componentDidUpdate
。当参考为null
时,在初始渲染时调用它。
如果在更改ref时仅应在后续渲染上调用它,则应为:
useEffect(() => {
if (!elRef.current)
return;
console.log("ref", elRef.current);
}, [elRef.current]);
答案 3 :(得分:0)
useEffect用作componentDidMount和componentDidUpdate, 在组件安装时,您添加了一个条件:
if (!user) return null;
return <div ref={elRef}>{user.first_name + " " + user.last_name}</div>;
由于在挂载时出现上述情况,因此您没有用户,因此它返回null,并且div未挂载在要添加ref的DOM中,因此在useEffect内部,您没有得到elRef的当前值值,因为它没有呈现。
然后在div安装在dom中时单击下一步,您将获得elRef.current的值。
答案 4 :(得分:0)
这里的假设是useEffect
需要检测对ref.current
的更改,因此需要在依赖项列表中包含ref
或ref.current
。我认为这是由于es-lint
过于-脚。
实际上,useEffect
的全部要点在于,它保证在渲染完成且DOM准备就绪之前不运行。这就是它处理副作用的方式。
因此,在执行useEffect
时,我们可以确定设置了elRef.current
。
代码的问题在于,直到填充<div ref={elRef}...>
之后,您才使用user
运行渲染器。因此,您要elRef
引用的DOM节点尚不存在。这就是为什么您获得null
日志记录的原因-与依赖关系无关。
顺便说一句:一种可能的替代方法是在效果挂钩中填充div:
useEffect(
() => {
if(!user) return;
elRef.current.innerHTML = `${user.first_name} ${user.last_name}`;
}, [user]
);
这样,用户组件中的if (!user) return null;
行就不需要了。删除它,并保证elRef.current
从一开始就填充div节点。