preactjs / preact-compat

ATTENTION: The React compatibility layer for Preact has moved to the main preact repo.
http://npm.im/preact-compat
MIT License
950 stars 148 forks source link

Transform React children to Preact children #503

Closed Bunlong closed 4 years ago

Bunlong commented 5 years ago

Hi @developit, How could I transform React children format to Preact children format?

/** @jsx h */
import Preact, { h } from "preact"
import React from 'react'

class PreactWidget extends React.Component {
  constructor() {
    super()
    this.divRef = React.createRef()
  }

  componentDidMount() {
    this.renderPreact()
  }

  componentDidUpdate() {
    this.renderPreact()
  }

  renderPreact() {
    const children = this.props.children

    Preact.render(
      children,
      this.divRef.current
    )
  }

  render() {
    let h = React.createElement
    return <div ref={this.divRef} />
  }
}

export default PreactWidget
class PreactComponent extends Preact.Component {
  render() {
    return <div>Hello World!</div>;
  }
}

class Benchmarks extends React.Component {
  render() {
    return(
      <PreactWidget>
        <PreactComponent />
      </PreactWidget>
    )
  }
}
Bunlong commented 5 years ago

Hi @developit Could you pls help to solve this issues for this project (preact-widget)? Thanks!

marvinhagemeister commented 5 years ago

It's hard to tell without more information like the error message you are getting. Guessing from your second code snippet it seems like you are mixing jsx factory functions from react and preact.

The easiest approach with least effort would be to use preact-compat and aliasing it to react imports instead of using react directly.

If you do not want to do this you'll have to put in quite a bit of work (it's doable though). I'm not sure about your goal (hard to tell without a description) but it seems like you want to use preact inside existing react projects and not convert the whole project from react to preact.

In this case things get a bit more complex because you have to deal with internal data structures. Basically you'd have to recursively convert the result of React.createElement(PreactComponent, null) (which will be the vnode structure of react), into preact's vnode structure. Inside the react codebase this is commonly referred to as ReactElement. This should be doable with a simple depth-first-search traversal.

The most obvious differences between react's and our vnode are these:

React Preact
vnode.type vnode.nodeName
vnode.props vnode.attributes
vnode.props.children vnode.children (must always be an array)

As mentioned the preact-compat codebase is a great reference for how the conversion is done.