英文:
Should state value of an input be inside the child or parent component?
问题
Here's the translated code portion with the explanation:
如果我有一个名为Profile
的个人资料页面的父组件,还有一个名为Post
的子组件。我想要引入一个功能,如果用户选择的话,更新帖子的内容。
我理解为什么最好将我要编辑的帖子的ID存储在父组件而不是子Post
组件内,因为我只想允许同时编辑一篇帖子。将我要编辑的帖子的ID存储在父组件中使我只能编辑一篇帖子,即在状态中的一篇帖子。
但是,我不确定如何使用React的最佳实践,特别是对于我想要成为正在编辑的帖子的新内容newContent
。用户键入的<input/>
内容应该存储在父组件还是子组件的状态中?
如果我将[newContent, setNewContent]
存储在父组件中,那么我将不得不将setNewContent
状态更新器传递给子组件,并在e.target.value
更改时更新状态。
如果我将其存储在子组件中,我只需将newContent
的当前状态传递给传递给Post组件的onEdit()
函数,但然后在进行更改后在何处或如何设置newContent(null)
会变得混乱。用户点击submitEdit
按钮后应该将其设置为null吗?在进行了帖子请求后的updatePostContent
函数内应该这样做吗?(这也让人感到困惑)
export default function Profile() {
const [posts, setPosts] = useState([]);
const [editingPostId, setEditingPostId] = useState(null);
const updatePostContent = async (id, newContent) => {
// 发送HTTP put请求来更新帖子,然后使用updatedPost更新帖子状态
};
return (
<div>
<h1>个人资料页面</h1>
<p>帖子:</p>
{posts.map((post) => (
<Post
key={post.id}
post={post}
isEditing={editingPostId === post.id}
onEdit={(newContent) => {
updatePostContent(post.id, newContent);
}}
cancelEdit={() => setEditingPostId(null)}
/>
))}
</div>
);
}
export function Post({ post, isEditing, onEdit, cancelEdit }) {
return (
<div>
<h1>{post.id}</h1>
<p>{post.content}</p>
{/* 如果正在编辑 */}
{isEditing && (
<>
<input type="text" onChange={(e) => console.log(e.target.value)} />
<button onClick={() => onEdit(newContent)}>提交编辑</button>
<button onClick={cancelEdit}>取消编辑</button>
</>
)}
</div>
);
}
只是不确定正确的"React"方式是什么。我的直觉告诉我,在子组件内部不需要存储newContent
状态,因为一次只能编辑一篇帖子,没有必要让子组件在其内部存储输入内容,这样意味着多个子组件会在不需要时拥有未使用的状态,因为一次只编辑一篇帖子。
你们推荐什么做法?
英文:
Say I have a parent component for a profile page called Profile
, and a child components called Post
. I would like to introduce a functionality that updates the content of a post if a user chooses.
I understand why its better to have the ID of the post I am editing in the parent component rather than inside the child Post
component, because I would like to only allow for editing one post at a time. Storing the ID of the post I am editing allows me to only edit a post at a time, the one that is in the state.
However I am not sure to go from here using React's best practices, specifically with the newContent
I would like to be the new content of the post being edited.
Should the <input/>
content being typed by the user, be stored in a state inside the parent or child component?
If I store for example [newContent, setNewContent]
inside the Parent, I would have to send the setNewContent
state updater to the child, and update the state on change with e.target.value
.
If I instead store it inside the child component, I would just send the current state of newContent
inside the onEdit()
function passed to the Post component, but then it gets confusing on where or how to then set the newContent(null)
after the change has been made. Should it be set to null after the user clicks submitEdit
button? inside the updatePostContent
function after the post request has been made? (this gets confusing too)
export default function Profile() {
const [posts, setPosts] = useState([]);
const [editingPostId, setEditingPostId] = useState(null);
const updatePostContent = async (id, newContent) => {
// HTTP put request to update post, and then updates the posts state with updatedPost
};
return (
<div>
<h1>Profile Page</h1>
<p>posts: </p>
{posts.map((post) => (
<Post
key={post.id}
post={post}
isEditing={editingPostId === post.id}
onEdit={(newContent) => {
updatePostContent(post.id, newContent);
}}
cancelEdit={() => setEditingPostId(null)}
/>
))}
</div>
);
}
export function Post({ post, isEditing, onEdit }) {
return (
<div>
<h1>{post.id}</h1>
<p>{post.content}</p>
{/* if is editing */}
{isEditing && (
<>
<input type="text" onChange={(e) => console.log(e.target.value)} />
<button onClick={() => onEdit(newContent)}>submit edit</button>
<button onClick={cancelEdit}>cancel editing</button>
</>
)}
</div>
);
}
Just not sure what the correct "React" way of doing this would be. My intuition tells me theres no need to store the newContent
state inside the child, since only one post can be edited a time, theres no need for the child component to store whatever is being typed by the input inside itself, since that would mean multiple child components would have a un-used states inside it when it is not really needed since only one post is being edited at once.
What would you guys recommend?
答案1
得分: 0
以下是翻译好的部分:
"Here's my two cents:" -> "以下是我的看法:"
"TLDR;" -> "简而言之;"
"Each component should be aware of its contents/values. That is the purpose of state in React." -> "每个组件都应该了解其内容/值。这就是React中状态的目的。"
"So, the child should have ownership of newContent. Once the value is submitted, the value should go back to the parent which it supplies back to the child in case of a 'display the content' or 'edit post' scenario." -> "因此,子组件应该拥有newContent的所有权。一旦值被提交,该值应返回给父组件,以便在“显示内容”或“编辑帖子”情况下将其提供给子组件。"
"Now, to the descriptive part:" -> "现在,进入详细部分:"
"In this case, the 'Post' component should be aware of the user input that is associated with it, in case it needs to perform some operations on the user input value. Once submitted, the value should be passed back to the 'Profile' component along with the post's identifier through a callback. The callback method would then store the submitted content against the respective identifier. Prior to the callback, you can clear up the input field on the 'Post' component." -> "在这种情况下,'Post'组件应该了解与其相关的用户输入,以防需要对用户输入值执行某些操作。一旦提交,该值应通过回调与帖子的标识一起传回到'Profile'组件。回调方法将随后根据相应的标识存储已提交的内容。在回调之前,您可以清除'Post'组件上的输入字段。"
"In case of a 'list the posts content' or 'edit post' scenario, the content is passed to the 'Post' component as a prop." -> "在“列出帖子内容”或“编辑帖子”的情况下,内容作为属性传递给'Post'组件。"
"Note: You can also consider to skip storing newContent value in the state of the 'Post' component altogether and directly pass the input value to the callback." -> "注意:您还可以考虑完全跳过在'Post'组件的状态中存储newContent值,并直接将输入值传递给回调。"
"Hope this helps." -> "希望这有所帮助。"
英文:
Here's my two cents:
TLDR;
Each component should be aware of its contents/values. That is the purpose of state in React. So, the child should have ownership of newContent. Once the value is submitted, the value should go back to the parent which it supplies back to the child in case of a 'display the content' or 'edit post' scenario.
Now, to the descriptive part:
In this case, the Post
component should be aware of the user input that is associated with it, in case it needs to perform some operations on the user input value. Once submitted, the value should be passed back to the Profile
component along with the post's identifier through a callback. The callback method would then store the submitted content against the respective identifier. Prior to the callback, you can clear up the input field on the Post
component.
In case of a 'list the posts content' or 'edit post' scenario, the content is passed to the Post
component as a prop.
Note: You can also consider to skip storing newContent value in the state of the Post
component altogether and directly pass the input value to the callback.
Hope this helps.
答案2
得分: 0
Option 1:
选项 1
如果原始状态(帖子数组)在父组件中,我会在父组件中更新状态并将 updatePostContent 作为 prop 传递给您的组件,您的组件中有您的更新“表单”。
Option 2:
选项 2
如果您需要经过多个组件传递 prop(prop drilling),我建议使用 useContext 钩子。
这里有一个关于上下文钩子的 Stack Overflow 回答:React - useContext。
英文:
This is how I would see it:
Option 1
If the original state (array with posts) is in the parent, I would update the state in the parent and pass the updatePostContent as a prop to your component where you have your update "form".
const Parent = () => {
const [posts, setPosts] = useState([]);
const updatePostContent = async (id, content) => {
// your logic here
}
return (
<div>
<h1>Profile Page</h1>
<p>posts: </p>
{posts.map((post) => (
<Post
key={post.id}
post={post}
updatePost={updatePostContent}
/>
))}
</div>
);
}
const Post = ({ post, isEditing, updatePost }) => {
const inputRef = useRef(null);
const submitChagne = () => {
// handle validation first, for example
updatePost(post.id, inputRef.current.value);
}
return (
<div>
<h1>{post.id}</h1>
<p>{post.content}</p>
{/* if is editing */}
{isEditing && (
<>
<input type="text" ref={inputRef} />
<button onClick={submitChange}>submit edit</button>
<button onClick={cancelEdit}>cancel editing</button>
</>
)}
</div>
);
}
In general I discourage prop drilling (extensive use of props through multiple components) but if it's just a direct parent, I don't see why not.
Option 2
If you have to go through a lot of components (prop drilling), I would suggest to use a useContext hook.
Here is a SO answer that explains the context hook a little: React - useContext
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论