Skip to content

Commit

Permalink
feat: refactor fragment helper in react ot handle keys (#1628)
Browse files Browse the repository at this point in the history
* feat: refactor fragment helper in react ot handle keys

* chore: update snapshots

* Update packages/docs/src/routes/docs/components/index.mdx

Co-authored-by: Sami Jaber <[email protected]>

* fix: issue with fragments without key

* chore: update snapshots

* chore: update snapshots

* chore: update snapshots

---------

Co-authored-by: Sami Jaber <[email protected]>
  • Loading branch information
nmerget and samijaber authored Nov 8, 2024
1 parent 697c307 commit 6f6db62
Show file tree
Hide file tree
Showing 40 changed files with 2,156 additions and 12 deletions.
10 changes: 10 additions & 0 deletions .changeset/long-ghosts-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@builder.io/mitosis': patch
---

[React] Refactor how `react` handles mitosis ``Fragment``.

Using ``import { Fragment } from '@builder.io/mitosis';
`` and `<Fragment key={option}>` in mitosis, generates an empty fragment in ``react`` target: `<>`. With this improvement the generated output will be `<React.Fragment key={`key-${option}`}>`. This will help to avoid issues with same keys e.g. inside for loops.


32 changes: 32 additions & 0 deletions packages/core/src/__tests__/__snapshots__/alpine.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1516,6 +1516,22 @@ exports[`Alpine.js > jsx > Javascript Test > arrowFunctionInUseStore 1`] = `
"
`;
exports[`Alpine.js > jsx > Javascript Test > basicForFragment 1`] = `
"<div x-data=\\"basicForFragment()\\">
<template x-for=\\"option in ['a', 'b', 'c']\\">
<div x-bind:key=\\"\`key-\${option}\`\\">
<div><span x-html=\\"option\\"></span></div>
</div>
</template>
</div>
<script>
document.addEventListener(\\"alpine:init\\", () => {
Alpine.data(\\"basicForFragment\\", () => ({}));
});
</script>
"
`;
exports[`Alpine.js > jsx > Javascript Test > basicForNoTagReference 1`] = `
"<state.TagNameGetter x-data=\\"myBasicForNoTagRefComponent()\\">
Hello
Expand Down Expand Up @@ -4521,6 +4537,22 @@ exports[`Alpine.js > jsx > Typescript Test > arrowFunctionInUseStore 1`] = `
"
`;
exports[`Alpine.js > jsx > Typescript Test > basicForFragment 1`] = `
"<div x-data=\\"basicForFragment()\\">
<template x-for=\\"option in ['a', 'b', 'c']\\">
<div x-bind:key=\\"\`key-\${option}\`\\">
<div><span x-html=\\"option\\"></span></div>
</div>
</template>
</div>
<script>
document.addEventListener(\\"alpine:init\\", () => {
Alpine.data(\\"basicForFragment\\", () => ({}));
});
</script>
"
`;
exports[`Alpine.js > jsx > Typescript Test > basicForNoTagReference 1`] = `
"<state.TagNameGetter x-data=\\"myBasicForNoTagRefComponent()\\">
Hello
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3327,6 +3327,48 @@ export class MyComponentModule {}
"
`;

exports[`Angular with Preserve Imports and File Extensions > jsx > Javascript Test > basicForFragment 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";

import { Component } from \\"@angular/core\\";

@Component({
selector: \\"basic-for-fragment\\",
template: \`
<div>
<ng-container
*ngFor=\\"let option of ['a', 'b', 'c']; trackBy: trackByOption0\\"
>
<ng-container>
<div>{{option}}</div>
</ng-container>
</ng-container>
</div>
\`,
styles: [
\`
:host {
display: contents;
}
\`,
],
})
export default class BasicForFragment {
trackByOption0(_, option) {
return \`key-\${option}\`;
}
}

@NgModule({
declarations: [BasicForFragment],
imports: [CommonModule],
exports: [BasicForFragment],
})
export class BasicForFragmentModule {}
"
`;

exports[`Angular with Preserve Imports and File Extensions > jsx > Javascript Test > basicForNoTagReference 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";
Expand Down Expand Up @@ -10887,6 +10929,48 @@ export class MyComponentModule {}
"
`;

exports[`Angular with Preserve Imports and File Extensions > jsx > Typescript Test > basicForFragment 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";

import { Component } from \\"@angular/core\\";

@Component({
selector: \\"basic-for-fragment\\",
template: \`
<div>
<ng-container
*ngFor=\\"let option of ['a', 'b', 'c']; trackBy: trackByOption0\\"
>
<ng-container>
<div>{{option}}</div>
</ng-container>
</ng-container>
</div>
\`,
styles: [
\`
:host {
display: contents;
}
\`,
],
})
export default class BasicForFragment {
trackByOption0(_, option) {
return \`key-\${option}\`;
}
}

@NgModule({
declarations: [BasicForFragment],
imports: [CommonModule],
exports: [BasicForFragment],
})
export class BasicForFragmentModule {}
"
`;

exports[`Angular with Preserve Imports and File Extensions > jsx > Typescript Test > basicForNoTagReference 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3372,6 +3372,49 @@ export class MyComponentModule {}
"
`;

exports[`Angular with Import Mapper Tests > jsx > Javascript Test > basicForFragment 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";

import { Component } from \\"@angular/core\\";

@Component({
selector: \\"basic-for-fragment\\",
template: \`
<div>
<ng-container
*ngFor=\\"let option of ['a', 'b', 'c']; trackBy: trackByOption0\\"
>
<ng-container>
<div>{{option}}</div>
</ng-container>
</ng-container>
</div>
\`,
styles: [
\`
:host {
display: contents;
}
\`,
],
})
export default class BasicForFragment {
trackByOption0(_, option) {
return \`key-\${option}\`;
}
}

@NgModule({
declarations: [BasicForFragment],
imports: [CommonModule],
exports: [BasicForFragment],
bootstrap: [SomeOtherComponent],
})
export class BasicForFragmentModule {}
"
`;

exports[`Angular with Import Mapper Tests > jsx > Javascript Test > basicForNoTagReference 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";
Expand Down Expand Up @@ -11055,6 +11098,49 @@ export class MyComponentModule {}
"
`;

exports[`Angular with Import Mapper Tests > jsx > Typescript Test > basicForFragment 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";

import { Component } from \\"@angular/core\\";

@Component({
selector: \\"basic-for-fragment\\",
template: \`
<div>
<ng-container
*ngFor=\\"let option of ['a', 'b', 'c']; trackBy: trackByOption0\\"
>
<ng-container>
<div>{{option}}</div>
</ng-container>
</ng-container>
</div>
\`,
styles: [
\`
:host {
display: contents;
}
\`,
],
})
export default class BasicForFragment {
trackByOption0(_, option) {
return \`key-\${option}\`;
}
}

@NgModule({
declarations: [BasicForFragment],
imports: [CommonModule],
exports: [BasicForFragment],
bootstrap: [SomeOtherComponent],
})
export class BasicForFragmentModule {}
"
`;

exports[`Angular with Import Mapper Tests > jsx > Typescript Test > basicForNoTagReference 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3434,6 +3434,48 @@ export class MyComponentModule {}
"
`;

exports[`Angular with manually creating and handling class properties as bindings (more stable) > jsx > Javascript Test > basicForFragment 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";

import { Component } from \\"@angular/core\\";

@Component({
selector: \\"basic-for-fragment\\",
template: \`
<div>
<ng-container
*ngFor=\\"let option of ['a', 'b', 'c']; trackBy: trackByOption0\\"
>
<ng-container>
<div>{{option}}</div>
</ng-container>
</ng-container>
</div>
\`,
styles: [
\`
:host {
display: contents;
}
\`,
],
})
export default class BasicForFragment {
trackByOption0(_, option) {
return \`key-\${option}\`;
}
}

@NgModule({
declarations: [BasicForFragment],
imports: [CommonModule],
exports: [BasicForFragment],
})
export class BasicForFragmentModule {}
"
`;

exports[`Angular with manually creating and handling class properties as bindings (more stable) > jsx > Javascript Test > basicForNoTagReference 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";
Expand Down Expand Up @@ -11247,6 +11289,48 @@ export class MyComponentModule {}
"
`;

exports[`Angular with manually creating and handling class properties as bindings (more stable) > jsx > Typescript Test > basicForFragment 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";

import { Component } from \\"@angular/core\\";

@Component({
selector: \\"basic-for-fragment\\",
template: \`
<div>
<ng-container
*ngFor=\\"let option of ['a', 'b', 'c']; trackBy: trackByOption0\\"
>
<ng-container>
<div>{{option}}</div>
</ng-container>
</ng-container>
</div>
\`,
styles: [
\`
:host {
display: contents;
}
\`,
],
})
export default class BasicForFragment {
trackByOption0(_, option) {
return \`key-\${option}\`;
}
}

@NgModule({
declarations: [BasicForFragment],
imports: [CommonModule],
exports: [BasicForFragment],
})
export class BasicForFragmentModule {}
"
`;

exports[`Angular with manually creating and handling class properties as bindings (more stable) > jsx > Typescript Test > basicForNoTagReference 1`] = `
"import { NgModule } from \\"@angular/core\\";
import { CommonModule } from \\"@angular/common\\";
Expand Down
Loading

0 comments on commit 6f6db62

Please sign in to comment.