Skip to content

Commit

Permalink
feat: refactor fragment helper in react ot handle keys
Browse files Browse the repository at this point in the history
  • Loading branch information
nmerget committed Nov 5, 2024
1 parent e430a68 commit 0efd1f3
Show file tree
Hide file tree
Showing 42 changed files with 2,532 additions and 296 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.


34 changes: 33 additions & 1 deletion packages/core/src/__tests__/__snapshots__/alpine.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1502,6 +1502,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 @@ -4493,6 +4509,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 Expand Up @@ -5669,7 +5701,7 @@ exports[`Alpine.js > jsx > Typescript Test > signalsOnUpdate 1`] = `
</style>
<div class=\\"test div\\" x-data=\\"myBasicComponent()\\">
<span x-html=\\"id\\"></span>
<span x-html=\\"foo.bar.baz\\"></span>
<span x-html=\\"foo.value.bar.baz\\"></span>
</div>
<script>
document.addEventListener(\\"alpine:init\\", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3294,6 +3294,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 @@ -10821,6 +10863,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 Expand Up @@ -13858,7 +13942,7 @@ type Props = {
@Component({
selector: \\"my-basic-component\\",
template: \`
<div class=\\"test div\\">{{id}} {{foo.bar.baz}}</div>
<div class=\\"test div\\">{{id}} {{foo.value.bar.baz}}</div>
\`,
styles: [
\`
Expand All @@ -13878,7 +13962,7 @@ export default class MyBasicComponent {
ngOnChanges(changes: SimpleChanges) {
if (typeof window !== \\"undefined\\") {
console.log(\\"props.id changed\\", this.id);
console.log(\\"props.foo.value.bar.baz changed\\", this.foo.bar.baz);
console.log(\\"props.foo.value.bar.baz changed\\", this.foo.value.bar.baz);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3338,6 +3338,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 @@ -10987,6 +11030,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 Expand Up @@ -14081,7 +14167,7 @@ type Props = {
@Component({
selector: \\"my-basic-component\\",
template: \`
<div class=\\"test div\\">{{id}} {{foo.bar.baz}}</div>
<div class=\\"test div\\">{{id}} {{foo.value.bar.baz}}</div>
\`,
styles: [
\`
Expand All @@ -14101,7 +14187,7 @@ export default class MyBasicComponent {
ngOnChanges(changes: SimpleChanges) {
if (typeof window !== \\"undefined\\") {
console.log(\\"props.id changed\\", this.id);
console.log(\\"props.foo.value.bar.baz changed\\", this.foo.bar.baz);
console.log(\\"props.foo.value.bar.baz changed\\", this.foo.value.bar.baz);
}
}
}
Expand Down
Loading

0 comments on commit 0efd1f3

Please sign in to comment.