In StrictMode, the useState() initializer function is called twice, but one of the results is discarded #20090
Description
React version: 17.0.1
React reconciler: 0.26.0
Steps To Reproduce
Link to code example: https://codesandbox.io/s/r3f-contact-shadow-forked-iggyv?file=/src/index.js:308-745
let log = console.log
let id = 0
function Obj(node) {
this.id = id++
log('constructor', this.id)
node.addEventListener('wheel', () => log(this.id, 'wheel'), false)
}
function App(props) {
// The object is created twice, why does react do that, it's not documented
const [obj] = useState(() => log('new object') || new Obj(document.body))
return <div>{obj.id}</div>
}
ReactDOM.unstable_createRoot(document.getElementById('root')).render(<App />)
old demo
https://codesandbox.io/s/r3f-contact-shadow-forked-e44m3?file=/src/index.js
This demo creates a local object which is supposed to live within the components lifecycle.
For some reason concurrent mode creates two versions of that object, but one is stuck in the view section.
These controls aren't allowed to zoom, yet, when you give you mousewheel - it zooms. The control clearly receives the flag.
This does not happen in blocking mode and previous reconcilers (for instance react 16.4.x and reconcilers pre 0.26
Debugging in this is almost impossible as React swallows console.logs. Some users have found out that it indeed creates two branches of local state: https://twitter.com/belinburgh/status/1319990608010874883
The state object (orbit-controls) has side-effects, it creates events, but that is and should be of no consequence.