useRef current 仅在第二次更新时获取其值
useRef current getting its value only on second update
我有以下组件:
const ParentComponent: React.FC = () => {
const networkRef: any = useRef();
// Somewhere in the code, I call this
networkRef.current.filter(["id0, id1, id2"]);
return (
...
<VisNetwork
ref={networkRef}
/>
...
)
}
export default ParentComponent;
interface Props {
ref: any;
}
const VisNetwork: React.FC<Props> = forwardRef((props: Props, ref) => {
useImperativeHandle(ref, () => ({
filter(items: any) {
setFilterNodes(items);
nView.refresh();
}
}));
const [filterNodes, setFilterNodes] = useState<any[]>([]);
const filterNodesRef = useRef(filterNodes);
useEffect(() => {
filterNodesRef.current = filterNodes;
}, [filterNodes]);
...
// Some code to create the network (concentrate on the nodesView filter method)
const [nView, setNView] = useState<DataView>();
const nodesView = new DataView(nodes, {
filter: (n: any) => {
if (filterNodesRef.current.includes(n.id)) {
return true;
}
return false;
}
})
setNView(nodesView);
const network = new vis.Network(container, {nodes: nodesView, edges: edgesView}, options);
});
export default VisNetwork;
当我调用 network.current.filter([...])
时,它会设置 filterNodes
状态。此外,它应该在 useEffect
.
中设置 filterNodesRef
但是,filterNodesRef.current
仍然是空数组。
但是当我第二次调用network.current.filter([...])
时,只有filterNodesRef.current
得到了值,DataView
才能够过滤。
为什么会这样?我认为 useRef.current
将始终包含最新值。
引用的 .current
设置不会将更改通知组件。一定有其他原因让它第二次起作用。
来自https://reactjs.org/docs/hooks-reference.html#useref
Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a callback ref instead.
您可能想要使用 useState
,因为这会重新呈现组件。
还有两件事
我不太确定 networkRef.current.filter(["id0, id1, id2"])
是什么。当我尝试做 ['a'].filter(['a'])
时,Typescript 确实会抱怨,但我从未见过这个,所以你确定这是你想要做的吗?
如果您要传递引用,可能有更好的方法。也许考虑重新考虑组件之间的关系。您这样做是因为您需要访问多个组件内的 networkRef
吗?如果是,您可能需要查看 providers.
如果这不能回答您的问题,请发表评论(请针对具体问题),我很乐意为您提供帮助:)
是的,useRef.current
包含最新值,但是 useEffect
中的 filterNodesRef.current
这就是为什么在初始渲染中得到空数组的原因。
VisNetwork
的初始渲染 filterNodes
是一个空数组 ==> filterNodesRef.current
仍然是空的。因为 setFilterNodes(items);
是异步函数 => 你在 useImperativeHandle
中设置的事件,它将在第二次渲染时更新。
在 useImperativeHandle
中你设置 setFilterNodes(items);
==> filterNodes 被更新并且 VisNetwork
重新渲染 ==> useEffect
被触发 = => filterNodesRef.current
设置为新的 filterNodes
让我们试试这个:
....
const filterNodesRef = useRef(filterNodes);
useImperativeHandle(ref, () => ({
filter(items: any) {
filterNodesRef.current = filterNodes;
setFilterNodes(items);
nView.refresh();
}
}));
...
我最终通过在 useEffect
中调用 refresh()
方法而不是 filter()
方法解决了这个问题:
useEffect(() => {
filterNodesRef.current = filterNodes;
nView.refresh();
}, [filterNodes]);
我有以下组件:
const ParentComponent: React.FC = () => {
const networkRef: any = useRef();
// Somewhere in the code, I call this
networkRef.current.filter(["id0, id1, id2"]);
return (
...
<VisNetwork
ref={networkRef}
/>
...
)
}
export default ParentComponent;
interface Props {
ref: any;
}
const VisNetwork: React.FC<Props> = forwardRef((props: Props, ref) => {
useImperativeHandle(ref, () => ({
filter(items: any) {
setFilterNodes(items);
nView.refresh();
}
}));
const [filterNodes, setFilterNodes] = useState<any[]>([]);
const filterNodesRef = useRef(filterNodes);
useEffect(() => {
filterNodesRef.current = filterNodes;
}, [filterNodes]);
...
// Some code to create the network (concentrate on the nodesView filter method)
const [nView, setNView] = useState<DataView>();
const nodesView = new DataView(nodes, {
filter: (n: any) => {
if (filterNodesRef.current.includes(n.id)) {
return true;
}
return false;
}
})
setNView(nodesView);
const network = new vis.Network(container, {nodes: nodesView, edges: edgesView}, options);
});
export default VisNetwork;
当我调用 network.current.filter([...])
时,它会设置 filterNodes
状态。此外,它应该在 useEffect
.
filterNodesRef
但是,filterNodesRef.current
仍然是空数组。
但是当我第二次调用network.current.filter([...])
时,只有filterNodesRef.current
得到了值,DataView
才能够过滤。
为什么会这样?我认为 useRef.current
将始终包含最新值。
引用的 .current
设置不会将更改通知组件。一定有其他原因让它第二次起作用。
来自https://reactjs.org/docs/hooks-reference.html#useref
Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a callback ref instead.
您可能想要使用 useState
,因为这会重新呈现组件。
还有两件事
我不太确定
networkRef.current.filter(["id0, id1, id2"])
是什么。当我尝试做['a'].filter(['a'])
时,Typescript 确实会抱怨,但我从未见过这个,所以你确定这是你想要做的吗?如果您要传递引用,可能有更好的方法。也许考虑重新考虑组件之间的关系。您这样做是因为您需要访问多个组件内的
networkRef
吗?如果是,您可能需要查看 providers.
如果这不能回答您的问题,请发表评论(请针对具体问题),我很乐意为您提供帮助:)
是的,useRef.current
包含最新值,但是 useEffect
中的 filterNodesRef.current
这就是为什么在初始渲染中得到空数组的原因。
VisNetwork
的初始渲染filterNodes
是一个空数组 ==>filterNodesRef.current
仍然是空的。因为setFilterNodes(items);
是异步函数 => 你在useImperativeHandle
中设置的事件,它将在第二次渲染时更新。在
useImperativeHandle
中你设置setFilterNodes(items);
==> filterNodes 被更新并且VisNetwork
重新渲染 ==>useEffect
被触发 = =>filterNodesRef.current
设置为新的filterNodes
让我们试试这个:
....
const filterNodesRef = useRef(filterNodes);
useImperativeHandle(ref, () => ({
filter(items: any) {
filterNodesRef.current = filterNodes;
setFilterNodes(items);
nView.refresh();
}
}));
...
我最终通过在 useEffect
中调用 refresh()
方法而不是 filter()
方法解决了这个问题:
useEffect(() => {
filterNodesRef.current = filterNodes;
nView.refresh();
}, [filterNodes]);