i used react useRef
in functional components to get link on html object and store it in Recoil atom. For example:
const Children = () => { const [refLink, setSrefLink] = useRecoilState(refLink) return <input ref={someRef}/> } const Parent = () => { const [refLink, setSrefLink] = useRecoilState(refLink) const someRef = useRef(); setSomeRef(someRef) return <Children />; } export const refLink = atom({ key: 'refLink', default: null , });
But when my Parent component ummounts I get error:
react-dom.development.js:20997 Uncaught TypeError: Cannot assign to read only property ‘current’ of object ‘#’ in file reac-dom.development.js
I can’t imagine what’s the problem;
Advertisement
Answer
The issue here is that atoms are are frozen by default (see the documentation) and a ref works by mutating the current
property of an object.
You could prevent object freezing by passing dangerouslyAllowMutability: true
.
export const refLinkState = atom({ key: 'refLink', default: null , dangerouslyAllowMutability: true, });
Note that this will only update all subscribers if the ref itself is replaced by another ref. If a ref consumer changes the current
property, subscribers will not re-render because the ref object is still the same object.
You could solve this by not using a ref, but by passing the ref value directly into your shared state.
// without dangerouslyAllowMutability export const refLinkState = atom({ key: 'refLink', default: null , }); const Children = () => { const [refLink, setRefLink] = useRecoilState(refLinkState); return <input ref={setRefLink} />; };
In the above scenario we’ve completely eliminated refs and instead store the DOM element in the recoil state without the ref wrapper.
However like the forward refs documentation mentions:
React components hide their implementation details, including their rendered output. Other components using
FancyButton
usually will not need to obtain a ref to the innerbutton
DOM element. This is good because it prevents components from relying on each other’s DOM structure too much.
Without knowing much about the structure and what exactly you want to achieve, you could for example extract the relevant data in Child
and store that in a shared state. But there is probably a better solution if we had more context.