I have the following components:
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;
WHen I call network.current.filter([...])
, it will set the filterNodes
state. Also, it should set the filterNodesRef
inside the useEffect
.
However, the filterNodesRef.current
remains to be empty array.
But when I call network.current.filter([...])
the second time, only then the filterNodesRef.current
got the value and the DataView
was able to filter.
Why is it like this? I thought the useRef.current
will always contain the latest value.
[2:52] In summary, useRef can be used to store data values just like useState, but the difference is that when that value changes, it doesn't cause a re-render.
useRef doesn't notify us when its content changes. Mutating the . current property doesn't cause a re-render. If we want to run some code when React attaches or detaches a ref to a DOM node, a callback ref is better suited.
The "Object is possibly null" error is caused because the useRef() hook can be passed an initial value as an argument and we're passing it null as an initial value. The hook returns a mutable ref object whose . current property is initialized to the passed argument.
I finally solved this by calling the refresh()
method inside the useEffect
instead of the filter()
method:
useEffect(() => {
filterNodesRef.current = filterNodes;
nView.refresh();
}, [filterNodes]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With