SOLIDJS:输入字段输入时失去焦点

发布于 2025-01-30 05:12:56 字数 2041 浏览 3 评论 0 原文

我有一个关于SolidJS的新手问题。我有一个带有对象的数组,例如待办事项列表。我将其作为带有输入字段的列表,以编辑这些对象中的属性之一。在输入字段之一中输入时,输入直接失去了焦点。

输入时,如何防止输入失去焦点?

这是一个代码框示例,说明了问题:

这是源代码演示问题:

import { render } from "solid-js/web";
import { createSignal, For } from 'solid-js'

function App() {
  const [todos, setTodos] = createSignal([
    { id: 1, text: 'cleanup' },
    { id: 2, text: 'groceries' },
  ])

  return (
    <div>
      <div>
        <h2>Todos</h2>
        <p>
          Problem: whilst typing in one of the input fields, they lose focus
        </p>
        <For each={todos()}>
          {(todo, index) => {
            console.log('render', index(), todo)
            return <div>
              <input
                value={todo.text}
                onInput={event => {
                  setTodos(todos => {
                    return replace(todos, index(), {
                      ...todo,
                      text: event.target.value
                    })
                  })
                }}
              />
            </div>
          }}
        </For>
        Data: {JSON.stringify(todos())}
      </div>
    </div>
  );
}

/*
 * Returns a cloned array where the item at the provided index is replaced
 */
function replace<T>(array: Array<T>, index: number, newItem: T) : Array<T> {
  const clone = array.slice(0)
  clone[index] = newItem
  return clone
}

render(() => <App />, document.getElementById("app")!);

update:我已经在问题和三个提出的解决方案(基于两个答案)(基于两个答案)中奏效了一个代码框示例:

I have a newbie question on SolidJS. I have an array with objects, like a to-do list. I render this as a list with input fields to edit one of the properties in these objects. When typing in one of the input fields, the input directly loses focus though.

How can I prevent the inputs to lose focus when typing?

Here is a CodeSandbox example demonstrating the issue: https://codesandbox.io/s/6s8y2x?file=/src/main.tsx

Here is the source code demonstrating the issue:

import { render } from "solid-js/web";
import { createSignal, For } from 'solid-js'

function App() {
  const [todos, setTodos] = createSignal([
    { id: 1, text: 'cleanup' },
    { id: 2, text: 'groceries' },
  ])

  return (
    <div>
      <div>
        <h2>Todos</h2>
        <p>
          Problem: whilst typing in one of the input fields, they lose focus
        </p>
        <For each={todos()}>
          {(todo, index) => {
            console.log('render', index(), todo)
            return <div>
              <input
                value={todo.text}
                onInput={event => {
                  setTodos(todos => {
                    return replace(todos, index(), {
                      ...todo,
                      text: event.target.value
                    })
                  })
                }}
              />
            </div>
          }}
        </For>
        Data: {JSON.stringify(todos())}
      </div>
    </div>
  );
}

/*
 * Returns a cloned array where the item at the provided index is replaced
 */
function replace<T>(array: Array<T>, index: number, newItem: T) : Array<T> {
  const clone = array.slice(0)
  clone[index] = newItem
  return clone
}

render(() => <App />, document.getElementById("app")!);

UPDATE: I've worked out a CodeSandbox example with the problem and the three proposed solutions (based on two answers): https://codesandbox.io/s/solidjs-input-field-loses-focus-when-typing-itttzy?file=/src/App.tsx

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

扛刀软妹 2025-02-06 05:12:57

使用的,将在项目更新时重新创建整个元素。更新项目时,您会失去焦点,因为带有焦点的元素(输入)以及其父(LI)被破坏,并创建了一个新元素。

您有两个选择。当创建新元素时,您可以手动将重点放在焦点时,或者在更新属性时保留元素的反应性更高。 indexArray 提供后者。

indexarray 在更新项目时保留元素引用。 索引组件使用 indexarray 在引擎盖下。

function App() {
  const [todos, setTodos] = createSignal([
    { id: 1, text: "cleanup" },
    { id: 2, text: "groceries" }
  ]);

  return (
    <ul>
      {indexArray(todos, (todo, index) => (
        <li>
          <input
            value={todo().text}
            onInput={(event) => {
              const text = event.target.value;
              setTodos(todos().map((v, i) => i === index ? { ...v, text } : v))
            }}
          />
        </li>
      ))}
    </ul>
  );
}

注意:组件内部缓存项目,以避免不必要的重新租户。未改变的项目将被重新使用,但更新的项目将被重新创建。

With For, whole element will be re-created when the item updates. You lose focus when you update the item because the element (input) with the focus gets destroyed, along with its parent (li), and a new element is created.

You have two options. You can either manually take focus when the new element is created or have a finer reactivity where element is kept while the property is updated. The indexArray provides the latter out of the box.

The indexArray keeps the element references while updating the item. The Index component uses indexArray under the hood.

function App() {
  const [todos, setTodos] = createSignal([
    { id: 1, text: "cleanup" },
    { id: 2, text: "groceries" }
  ]);

  return (
    <ul>
      {indexArray(todos, (todo, index) => (
        <li>
          <input
            value={todo().text}
            onInput={(event) => {
              const text = event.target.value;
              setTodos(todos().map((v, i) => i === index ? { ...v, text } : v))
            }}
          />
        </li>
      ))}
    </ul>
  );
}

Note: For component caches the items internally to avoid unnecessary re-renders. Unchanged items will be re-used but updated ones will be re-created.

幸福不弃 2025-02-06 05:12:56

&lt; for&gt; 组件按参考数组的键项。
当您使用替换更新todos中的待办事项时,您将创建一个全新的对象。然后,固体将新对象视为完全无关的项目,并为其创建新的HTML元素。

您可以改用 streateStore ,仅更新todo对象的单个属性,而无需更改对其的引用。

const [todos, setTodos] = createStore([
   { id: 1, text: 'cleanup' },
   { id: 2, text: 'groceries' },
])
const updateTodo = (id, text) => {
   setTodos(o => o.id === id, "text", text)
}

或使用替代控制流量组件来映射输入数组,该数组具有明确的密钥属性:
https://github.com/solidjs-community/solid/solid/solid - primitives/tree/main/packages/keyed#key

<Key each={todos()} by="id">
   ...
</Key>

<For> components keys items of the input array by the reference.
When you are updating a todo item inside todos with replace, you are creating a brand new object. Solid then treats the new object as a completely unrelated item, and creates a fresh HTML element for it.

You can use createStore instead, and update only the single property of your todo object, without changing the reference to it.

const [todos, setTodos] = createStore([
   { id: 1, text: 'cleanup' },
   { id: 2, text: 'groceries' },
])
const updateTodo = (id, text) => {
   setTodos(o => o.id === id, "text", text)
}

Or use an alternative Control Flow component for mapping the input array, that takes an explicit key property:
https://github.com/solidjs-community/solid-primitives/tree/main/packages/keyed#Key

<Key each={todos()} by="id">
   ...
</Key>
别低头,皇冠会掉 2025-02-06 05:12:56

@Thetarnav解决方案可以使用,我想提出自己的建议。
我将通过&lt; index&gt; 来解决它

import { render } from "solid-js/web";
import { createSignal, Index } from "solid-js";

/*
 * Returns a cloned array where the item at the provided index is replaced
 */
function replace<T>(array: Array<T>, index: number, newItem: T): Array<T> {
  const clone = array.slice(0);
  clone[index] = newItem;
  return clone;
}

function App() {
  const [todos, setTodos] = createSignal([
    { id: 1, text: "cleanup" },
    { id: 2, text: "groceries" }
  ]);

  return (
    <div>
      <div>
        <h2>Todos</h2>
        <p>
          Problem: whilst typing in one of the input fields, they lose focus
        </p>
        <Index each={todos()}>
          {(todo, index) => {
            console.log("render", index, todo());
            return (
              <div>
                <input
                  value={todo().text}
                  onInput={(event) => {
                    setTodos((todos) => {
                      return replace(todos, index, {
                        ...todo(),
                        text: event.target.value
                      });
                    });
                  }}
                />
              </div>
            );
          }}
        </Index>
        Dat: {JSON.stringify(todos())}
      </div>
    </div>
  );
}
render(() => <App />, document.getElementById("app")!);

,而不是 index 是函数/信号,现在对象为。这允许框架替换文本框内联的值。
要记住它的工作原理:用于通过参考记住您的对象。如果您的对象切换位置,则可以重复使用相同的对象。 索引通过索引记住您的值。如果更改了某个索引的值,则反映在信号中。

该解决方案并不比其他提出的解决方案更正确,但是我觉得这更沿线,更接近固体的核心。

While @thetarnav solutions work, I want to propose my own.
I would solve it by using <Index>

import { render } from "solid-js/web";
import { createSignal, Index } from "solid-js";

/*
 * Returns a cloned array where the item at the provided index is replaced
 */
function replace<T>(array: Array<T>, index: number, newItem: T): Array<T> {
  const clone = array.slice(0);
  clone[index] = newItem;
  return clone;
}

function App() {
  const [todos, setTodos] = createSignal([
    { id: 1, text: "cleanup" },
    { id: 2, text: "groceries" }
  ]);

  return (
    <div>
      <div>
        <h2>Todos</h2>
        <p>
          Problem: whilst typing in one of the input fields, they lose focus
        </p>
        <Index each={todos()}>
          {(todo, index) => {
            console.log("render", index, todo());
            return (
              <div>
                <input
                  value={todo().text}
                  onInput={(event) => {
                    setTodos((todos) => {
                      return replace(todos, index, {
                        ...todo(),
                        text: event.target.value
                      });
                    });
                  }}
                />
              </div>
            );
          }}
        </Index>
        Dat: {JSON.stringify(todos())}
      </div>
    </div>
  );
}
render(() => <App />, document.getElementById("app")!);

As you can see, instead of the index being a function/signal, now the object is. This allows the framework to replace the value of the textbox inline.
To remember how it works: For remembers your objects by reference. If your objects switch places then the same object can be reused. Index remembers your values by index. If the value at a certain index is changed then that is reflected in the signal.

This solution is not more or less correct than the other one proposed, but I feel this is more in line and closer to the core of Solid.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文