[英]How do I update a single item in list with React Context?
我真的很喜欢 React 上下文,但我认为它缺少一些东西(或者我不知道该怎么做)
假设我有一个待办事项列表,它是相应的提供者
const Home = () => (
<div className="container">
<TodosProvider>
<TodosList />
</TodosProvider>
</div>
)
const TodosList = () => {
const { todos } = useTodos();
return (
<>
{todos.map((todo, idx) => (
<SingleTodo />
))}
</>
)
}
在另一个文件中
import { createContext, useContext, useState } from "react";
const TodosContext = createContext({});
export const TodosProvider = ({ children }) => {
const [todos, setTodos] = useState([{ text: 'a' }, { text: 'b' }, { text: 'c' }])
return (
<TodosContext.Provider value={{ todos }}>
{children}
</TodosContext.Provider>
)
}
export const useTodos = () => {
const todos = useContext(TodosContext)
return todos
}
我如何在 SingleTodo 中更新单个待办事项而无需:
1) 将 map idx 作为属性传递给 SingleTodo,然后从 SingleTodo 调用 TodosList 提供程序的方法,将 idx 作为参数传递
2) 给 todo 一个人工的 id 属性。 然后在 TodosProvider 中更新与该 id 匹配的待办事项。
这些限制的原因是:
1) 将渲染中todo的position作为prop传递下去,使使用context的好处失效,即不必做prop drilling
2)我认为仅仅为了 state 管理而用人工 id 污染 model 是不好的。
我希望能够在循环的每次迭代中创建一个 SingleTodoContext 并实例化一个 SingleTodoProvider
const TodosList = () => {
const { todos } = useTodos();
return (
<>
{todos.map((todo, idx) => (
<SingleTodoProvider key={idx} loadFrom={todo}>
<SingleTodo />
</SingleTodoProvider>
))}
</>
)
}
但这不起作用,因为提供者随后需要将 loadFrom 属性存储为 state,这会破坏列表待办事项和单个待办事项之间的同步。
那么,如何在不钻取列表中项目的 position 的情况下更新列表中的单个项目? 我不想使用 Redux
您可以将用于更新上下文中的值的方法作为上下文的一部分传递。 这是一个基于您的代码的 示例(有点挤在一起):
import React from "react";
import "./styles.css";
import { createContext, useContext, useState } from "react";
const TodosContext = createContext({});
export const TodosProvider = ({ children }) => {
const [todos, setTodos] = useState([
{ text: "a" },
{ text: "b" },
{ text: "c" }
]);
const selectTodo = (todo, idx) => {
console.log(
"do something with the todo here and then call setTodos, or something else?",
todo.text,
idx
);
// setTodos(prev => /* Do something here to update the list */)
};
return (
<TodosContext.Provider value={{ selectTodo, todos }}>
{children}
</TodosContext.Provider>
);
};
export const useTodos = () => {
const todos = useContext(TodosContext);
return todos;
};
const Home = () => (
<div className="container">
<TodosProvider>
<TodosList />
</TodosProvider>
</div>
);
const SingleTodo = ({ todo, onClick }) => (
<div>
{todo.text} <button onClick={() => onClick(todo)}>Click Me!</button>
</div>
);
const TodosList = () => {
const { selectTodo, todos } = useTodos();
return todos.map((todo, idx) => (
<SingleTodo onClick={todo => selectTodo(todo, idx)} todo={todo} key={idx} />
));
};
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Home />
</div>
);
}
希望有帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.