Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fast refresh duplicates HOC wrapped list items #307

Open
dashzt opened this issue Mar 22, 2021 · 4 comments
Open

fast refresh duplicates HOC wrapped list items #307

dashzt opened this issue Mar 22, 2021 · 4 comments
Labels
bug Something isn't working

Comments

@dashzt
Copy link

dashzt commented Mar 22, 2021

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)
image

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
image

@JoviDeCroock
Copy link
Member

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?

@dashzt
Copy link
Author

dashzt commented Mar 24, 2021

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

@JoviDeCroock
Copy link
Member

JoviDeCroock commented Mar 24, 2021

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

@JoviDeCroock
Copy link
Member

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

@JoviDeCroock JoviDeCroock added the bug Something isn't working label Feb 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants