Skip to content

Latest commit

 

History

History
119 lines (89 loc) · 2.52 KB

caveats.md

File metadata and controls

119 lines (89 loc) · 2.52 KB

Caveats

We try to maximize compatibility between React & Svelte. However, there are some inherent limitations to be aware of.

Binding

React components are one directional by design, therefor you can't two-way bind to a prop:

<react.input bind:value />
❌

Listen to events instead:

<react.input
  {value}
  onInput={(e) => {
    value = e.currentTarget.value;
  }}
/>
✅

No JSX

JSX is not supported inside *.svelte files:

<react.MenuItem
  icon={<react.Icon icon="book" />}
  label="Books"
/>
❌

Use the non-jsx syntax:

<script>
  import { createElement } from "react";
</script>

<react.MenuItem icon={createElement(Icon, { icon: "book" })} label="Books" />
✅

Children incompatibility

React children and Svelte children are fundamentally different.

In Svelte children are a Snippet or undefined. You can't do much besides {@render children?.()}. This improved encapsulation and predictability, but is less flexible than React.

In React, children can be any type and can be inspected, modified or used in way.

Svelte/React input:

<react.p>
  <h1>Content</h1>
</react.p>

React vDOM output:

<Bridge>
  <SvelteToReactContext.Provider>
    <p>
      <Bridge>
        <SvelteToReactContext.Provider>
          <Child /> <- When merging the render trees the <h1>Content</h1> is injected here
        </SvelteToReactContext.Provider>
      </Bridge>
    </p>
  </SvelteToReactContext.Provider>
</Bridge>

HTML output:

<svelte-portal-x-target style="display: contents;">
  <p>
    <react-children-x-target style="display: contents;">
      <svelte-children-x-source style="display: contents;">
        <h1>Content</h1>
      </svelte-children-x-source>
    </react-children-x-target>
  </p>
</svelte-portal-x-target>

There are cases where the React virtual DOM or this real DOM can cause problems. A workaround is write a react wrapper component that create the wanted structure and use that component inside Svelte.

Render props

<react.SearchResults>{async (query) => fetchResults(query))}</react.SearchResults>
❌

Use the children prop instead:

<react.SearchResults children={ async (query) => fetchResults(query)) } />
✅

Synchronous rendering

We render 2 trees, one for Svelte and one for React and then merge their output.

Because the Svelte server rendering synchronous, we must also use the synchronous api in React. Therefor we use the renderToString instead of the newer renderToPipeableStream api.