我正在学习
signals
功能并遇到了一些问题:
value={newTodo.value}
那么我就无法在输入字段中输入内容,只能输入一个字符。value={newTodo}
,我可以在输入字段中输入内容,但当我单击按钮添加新的待办事项时,我的待办事项列表 todos
永远不会在 UI 中更新/重新渲染,即使 console.log
显示列表已更新已经。但是如果我改回反应钩子,一切都会正常。有人可以帮忙吗?谢谢!
我还为此问题创建了一个沙箱。
import { signal, effect } from "@preact/signals-react"
import { useState } from "react"
export default function SignalsTodolist() {
const todos = signal(["eat", "sleep", "play video game"])
const newTodo = signal("")
const addNewTodo = (e) => {
e.preventDefault()
todos.value = [...todos.value, newTodo.value]
console.log(todos.value)
newTodo.value = "" // Use setNewTodo to update the state
}
// const resetToto = () => {
// newTodos(["eat", "sleep", "play video game"])
// }
return (
<div>
Create a todo list with signals。
<br />
<br />
<input
type="text"
value={newTodo}. // highlight
onChange={(e) => (newTodo.value = e.target.value)}
placeholder="Type to add..."
/>
<button type="submit" onClick={addNewTodo}>
add new todo
</button>
<br />
{newTodo}, {todos} {/* To display the array */}
<ul>
{todos.value.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
)
}
signal(...)
在每个渲染上创建新实例。当您更新它时,会发生重新渲染,然后信号会为您提供初始实例。您不应该在组件内部使用它。将其移到外面或使用 useSignal
https://preactjs.com/guide/v10/signals/#local-state-with-signals
经过一些研究......也许尝试使用
batch
来确保项目已更新/重新渲染。
preact 非常脆弱,因为最小的东西都可能搞砸 - 我一直在弄乱几个不同的沙箱,这似乎是最好的工作示例,但对于一个简单的待办事项列表来说有很多开销https:// codesandbox.io/p/sandbox/preact-signals-react-5qcp8r
TodoList.js
import { signal, computed, batch } from "@preact/signals-react";
import { useAppState } from "./AppStateContext";
const newItem = signal("");
export default function TodoList() {
const { todos, addTodo, removeTodo } = useAppState();
const completedCount = computed(() => {
return todos.value.filter((todo) => todo.completed).length;
});
const onInput = (event) => (newItem.value = event.target.value);
const onAddClick = () => {
batch(() => {
addTodo(newItem);
newItem.value = "";
});
};
return (
<>
<input type="text" value={newItem.value} onInput={onInput} />
<button style={{ marginLeft: "10px" }} onClick={onAddClick}>
Add
</button>
<ul style={{ textAlign: "left" }}>
{todos.value.map((todo, index) => {
return (
<li>
<input
type="checkbox"
checked={todo.completed}
onInput={() => {
todo.completed = !todo.completed;
todos.value = [...todos.value];
}}
/>
{todo.completed ? <s>{todo.text}</s> : todo.text}{" "}
<button
style={{ marginLeft: "10px", color: "red" }}
onClick={() => removeTodo(index)}
>
x
</button>
</li>
);
})}
</ul>
<p>Completed count: {completedCount.value}</p>
</>
);
}
AppContext.js
import React, { useContext } from "react";
import { signal } from "@preact/signals-react";
const AppState = React.createContext();
function AppStateProvider(props) {
const todos = signal([
{ text: "eat", completed: true },
{ text: "sleep", completed: false },
{ text: "rave", completed: false },
{ text: "repeat", completed: false }
]);
function addTodo(newItem) {
todos.value = [...todos.value, { text: newItem.value, completed: false }];
}
function removeTodo(index) {
todos.value.splice(index, 1);
todos.value = [...todos.value];
}
return (
<AppState.Provider value={{ todos, addTodo, removeTodo }}>
{props.children}
</AppState.Provider>
);
}
function useAppState() {
const appState = useContext(AppState);
if (!appState) {
throw new Error("useAppState must be used within a AppStateProvider");
}
return appState;
}
export { AppStateProvider, useAppState };
据我从使用 preact 的公司同事那里听到的消息,除非你每次都完美地使用它,否则信号等可能会成为一场噩梦。另外,您的代码问题可能是因为 preact 与您的框架交互的方式,因为正如 preact 文档所述,当您更新值时,它应该导致重新渲染,但显然不是
即使在给出的示例中,状态也没有按预期完全工作...尝试删除未选中的项目,然后检查新项目或在尝试删除未选中的项目后添加项目..您会看到一些明显的渲染问题..preact 也是suuuuper new所以除非你必须使用它,否则可能会踢它并密切关注它,直到它与其他框架(如反应)相比具有更高的稳定性