Quick React Mistakes
1 Things NOT to do
- useEffect with a
bleh.current
Ref as a dependency
const bleh = useRef(..)
useEffect(()=>{..},[bleh.current]);
2 Referential equality
function Foo({bar, baz}) {
const options = {bar, baz}
.useEffect(() => {
Reactbuzz(options)
, [options]) // we want this to re-run if bar or baz change
}return <div>foobar</div>
}
function Blub() {
return <Foo bar="bar value" baz={3} />
}
useEffect
is worthless in the above scenario since js will say each new rerender of options is “different”
function Foo({bar, baz}) {
.useEffect(() => {
Reactconst options = {bar, baz}
buzz(options)
, [bar, baz]) // we want this to re-run if bar or baz change
}return <div>foobar</div>
}
The above works but ONLY IF bar and baz are primitive types. If we defined bar and baz as a function and list type, the above would fail.
function Foo({bar, baz}) {
.useEffect(() => {
Reactconst options = {bar, baz}
buzz(options)
, [bar, baz])
}return <div>foobar</div>
}
function Blub() {
const bar = React.useCallback(() => {}, [])
const baz = React.useMemo(() => [1, 2, 3], [])
return <Foo bar={bar} baz={baz} />
}
The above now works.
3 Objects and useEffect, referential equality
https://dev.to/vicnovais/understanding-referential-equality-in-reacts-useeffect-2m7o
useEffect
detects REFERENTIAL EQUALITY- When a object is passed to
useEffect
dependency, even if we mutate the object, the reference to the object doesnt change
3.1 useRef and useEffect chaos
const myref = useRef()
creates an objectmyref
myref
is an object with a property calledcurrent
- even if
myref.current
changes, aka the DOMElement changes,myref
the object itself maintains the same reference since only the propertycurrent
changed.
- useEffect only detects referential equality.
For those reasons above
useEffect(()=>{},[myref])
doesnt work
but… what if we did useEffect(()=>{},[myref.current])
?
We naively expect it to work since myref.current
does change reference BUT REMEMBER even if myref.current
changes meaning the DOM changed, it does not trigger a react rerender.
useEffect only works when a rerender is triggered, meaning it will never trigger.
Example is D3 controlling the DOM, D3 does not trigger rerenders therefore useEffect on D3 controlled elements wont work!!
4 Nested component definition
//DO NOT DO THIS
const OuterComponent = () => {
const [getstate,setstate] = useState();
const InnerComponent = () => {
return(
<input type="text" onChange={(e)=>setstate(..)}>
)
}return(
<>
<InnerComponent/>
</>
) }
//DO THIS
const InnerComponent = ({setstate}) => {
return(
<input type="text" onChange={(e)=>setstate(..)}>
)
}
const OuterComponent = () => {
const [getstate,setstate] = useState();
return(
<>
<InnerComponent setstate={setstate}/>
</>
) }
WHY: Whenever OuterComponent rerenders, it redeclares the InnerComponent. The InnerComponent of the snd render is different from the InnerComponent from the first render so you lose the text and lose focus on the textbox.
This is what the react offical docs talk about “lifting state up to the parent component”.
WARN: Do not mistake “lifting state up” to mean nesting definitions.
https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unstable-nested-components.md