prefresh
prefresh copied to clipboard
fast refresh duplicates HOC wrapped list items
Dependancies:
"@prefresh/babel-plugin": "^0.4.1"
"@prefresh/webpack": "^3.2.0"
"webpack": "^4.46.0",
"webpack-dev-server": "^3.11.2",
"webpack-hot-middleware": "^2.25.0",
"preact": "^10.5.12"
webpack is set up to use preact/compat
There are following files: HOC.jsx // This just represents generic HOC. Originally I faced this issue when using useIntl from 'react-intl' and withTheme from 'styled-components' and it can be reproduced using them as well
import React from 'react'
export const applyHOC = (Component) => (props) => <Component {...props} HOCApplied={true} />
List.jsx
import React from 'react'
import Item from './ListItem'
const items = [0, 1, 2, 3]
export const List = () => {
return <div>{items.map(item => <Item key={`item-${item}`} index={item}/>)}</div>
}
ListItem.jsx
import React, { Component } from 'react'
import { applyHOC } from './HOC'
class ListItem extends Component {
render() {
return <div>item {this.props.index}</div>
}
}
const WrappedListItem = applyHOC(ListItem)
export default WrappedListItem
With this set up whenever I try to change ListItem.jsx all items in List are duplicated. (For example I've added word 'updated' to ListItem content)
I've also tried playing with displayName in different ways, but for me it gave no result at all
I've found that if I move wrapping ListItem with HOC to separate file this flow works fine and list items are never duplicated.
So, if I change files to be: List.jsx
import React from 'react'
import Item from './WrappedListItem'
const items = [0, 1, 2, 3]
export const List = () => {
return <div>{items.map(item => <Item key={`item-${item}`} index={item}/>)}</div>
}
ListItem.jsx
import React, { Component } from 'react'
class ListItem extends Component {
render() {
return <div>item {this.props.index}</div>
}
}
export default ListItem
WrappedListItem.jsx
import { applyHOC } from './HOC'
import Item from './ListItem'
export default applyHOC(Item)
Then I have following result doing same steps as before
Hey,
I've been thinking about what could be the issue here, I keep coming back to the referential identity part and this being a possible Preact child-diffing bug.
If I understand this correctly you can't HMR WrappedListItem
but you can HMR ListItem
with your workaround? This means that we might need to account for the case where the identity of a component changes between module-injections. Because the HOC injects a series of unnamed components.
export const applyHOC = (Component) => function Wrapper(props) { return <Component {...props} HOCApplied={true} /> }
would for instance name the returning component from applyHOC
to Wrapper
, no clue if this is sufficient?
Hey.
I don't face any issues with my workaround, all components seems to hot replace fine, even if returning unnamed function from HOC. I've just added this as possible solution.
The only issue I see is duplicating components, which i've described in the first part of this issue
So I've just tried this setup in the test/fixture/next
folder and don't seem to be running into this.
Changed return <div>item {this.props.index}</div>
to return <div>i{this.props.index}</div>
and it worked correcly, am I missing smth?
EDIT: oh I figured it out it only happens on the second save
I'm not entirely sure if we can build a guard for this but this seems to be because of how the update propagates through the tree, the children get duplicated after a while. Trying to figure out if I can guard for this somehow or if this is something that will be for the restructure
release of Preact