Repository: Rezact/Rezact
Pull request #11 (2023-09-26 13:17:49)

Simple string list bug
```tsx
export function Page() {
  // This PR fixes a bug where the cached element references caused 
  // a simple string list not to be rendered correctly if there were more than one map over it
  let $test = ["Jack", "Jill", "John", "Jane"];
  return (
    <>
      <h1>Simple String List</h1>

      {$test.map(($name) => (
        <div dataVal={$name}>
          <input value={$name} />
        </div>
      ))}

      {$test.map(($name) => (
        <div>{$name}</div>
      ))}
    </>
  );
}
```


Patch:
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..1902c8d
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,31 @@
+name: Publish to npm
+
+on:
+  push:
+    tags:
+      - "v*" # This will run the workflow when you push a new tag that starts with 'v'
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v4
+
+      - name: Setup Node.js
+        uses: actions/setup-node@v3
+        with:
+          node-version: "18" # Use the version of Node.js you are using
+          registry-url: "https://registry.npmjs.org"
+
+      - name: Install dependencies
+        run: npm ci
+
+      - name: Build
+        run: npm run build # If you have a build script, run it here
+
+      - name: Publish
+        run: cd dist && npm publish
+        env:
+          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/package.json b/package.json
index 2a53aa0..24e227d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@rezact/rezact",
-  "version": "1.0.15-beta.12",
+  "version": "1.0.15-beta.13",
   "type": "module",
   "description": "Intuitive Reactivity, Simplified State. Embrace a modern UI framework that encourages direct data mutations, offers module-level reactivity, and simplifies component design. With Rezact, you get the power of reactivity without the boilerplate. Dive into a seamless development experience tailored for today's web.",
   "main": "index.cjs",
diff --git a/src/components/appRouter.ts b/src/components/appRouter.ts
index 6ae7d67..c0a77cf 100644
--- a/src/components/appRouter.ts
+++ b/src/components/appRouter.ts
@@ -68,4 +68,9 @@ router.addRoute(
 
 router.addRoute("/store-test", () => import("src/examples/StoreTest/App"));
 
+router.addRoute(
+  "/simple-string-list",
+  () => import("src/examples/SimpleStringListState/SimpleStringList")
+);
+
 export { router };
diff --git a/src/examples/Layout/nestedLayout.tsx b/src/examples/Layout/nestedLayout.tsx
index 4ba8c91..dee75f7 100644
--- a/src/examples/Layout/nestedLayout.tsx
+++ b/src/examples/Layout/nestedLayout.tsx
@@ -65,6 +65,9 @@ export function MyLayout({ Component, pageProps }: any) {
         <li>
           <a href="/list-redraw">List Redraw</a>
         </li>
+        <li>
+          <a href="/simple-string-list">Simple String List</a>
+        </li>
         <li>
           <a href="/asdfasdfasdfasdf">A Route that does not exist</a>
         </li>
diff --git a/src/examples/SimpleStringListState/SimpleStringList.tsx b/src/examples/SimpleStringListState/SimpleStringList.tsx
new file mode 100644
index 0000000..87e3807
--- /dev/null
+++ b/src/examples/SimpleStringListState/SimpleStringList.tsx
@@ -0,0 +1,22 @@
+// import { xCreateElement, xFragment } from "rezact";
+import { MyLayout } from "../Layout/nestedLayout";
+
+export function Page() {
+  let $test = ["Jack", "Jill", "John", "Jane"];
+  return (
+    <>
+      <h1>Simple String List</h1>
+
+      {$test.map(($name) => (
+        <div dataVal={$name}>
+          <input value={$name} />
+        </div>
+      ))}
+      {$test.map(($name) => (
+        <div>{$name}</div>
+      ))}
+    </>
+  );
+}
+
+export const Layout = MyLayout;
diff --git a/src/lib/rezact/mapState.ts b/src/lib/rezact/mapState.ts
index 200d254..4bed02c 100644
--- a/src/lib/rezact/mapState.ts
+++ b/src/lib/rezact/mapState.ts
@@ -171,8 +171,7 @@ export class MapState extends BaseState {
       )
         item.elmRef = undefined;
 
-      item.elmRef =
-        cachedElmRef || item.elmRef || createComponent({ func, item });
+      item.elmRef = cachedElmRef || createComponent({ func, item });
       if (!cachedElmRef) this.elmRefCache.set(item, item.elmRef);
 
       if (!item.nestedSubscribed) {


Test patch:
diff --git a/src/examples/SimpleStringListState/__snapshots__/simpleStringListState.test.ts.snap b/src/examples/SimpleStringListState/__snapshots__/simpleStringListState.test.ts.snap
new file mode 100644
index 0000000..9a42a4f
--- /dev/null
+++ b/src/examples/SimpleStringListState/__snapshots__/simpleStringListState.test.ts.snap
@@ -0,0 +1,5 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`Simple String List State > Renders both input list and output list 1`] = `"<h1>Simple String List</h1><!--start map--><div dataval=\\"[object Text]\\"><input></div><div dataval=\\"[object Text]\\"><input></div><div dataval=\\"[object Text]\\"><input></div><div dataval=\\"[object Text]\\"><input></div><!--end map--><!--start map--><div>Jack</div><div>Jill</div><div>John</div><div>Jane</div><!--end map--><!--signal-->"`;
+
+exports[`Simple String List State > updates state when input is changed 1`] = `"<h1>Simple String List</h1><!--start map--><div dataval=\\"Jackhello\\"><input></div><div dataval=\\"Jillhello\\"><input></div><div dataval=\\"Johnhello\\"><input></div><div dataval=\\"Janehello\\"><input></div><!--end map--><!--start map--><div>Jackhello</div><div>Jillhello</div><div>Johnhello</div><div>Janehello</div><!--end map--><!--signal-->"`;
diff --git a/src/examples/SimpleStringListState/simpleStringListState.test.ts b/src/examples/SimpleStringListState/simpleStringListState.test.ts
new file mode 100644
index 0000000..cee8c91
--- /dev/null
+++ b/src/examples/SimpleStringListState/simpleStringListState.test.ts
@@ -0,0 +1,28 @@
+import { describe, expect, it } from "vitest";
+import { render } from "rezact";
+import { Page } from "./SimpleStringList";
+import userEvent from "@testing-library/user-event";
+
+const user = userEvent.setup();
+
+describe("Simple String List State", () => {
+  it("Renders both input list and output list", async () => {
+    render(document.body, Page);
+    await delay(100);
+    expect(document.body.innerHTML).toMatchSnapshot();
+  });
+
+  it("updates state when input is changed", async () => {
+    const inputs = document.querySelectorAll("input");
+    await user.type(inputs[0], "hello");
+    await user.type(inputs[1], "hello");
+    await user.type(inputs[2], "hello");
+    await user.type(inputs[3], "hello");
+
+    await delay(100);
+
+    expect(document.body.innerHTML).toMatchSnapshot();
+  });
+});
+
+const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));