Kir*_*ran 5 javascript reactjs react-hooks use-effect use-state
我写了以下代码:
function CreateModal({toggleCreatePorjectModal, fetchProjects}) {
const [formObj, setFormObj] = useState({name: "", link: "", error: ""})
function validateLinkAndCreateProject() {
if(formObj.link.trim() === "" || formObj.name.trim() === "") {
setFormObj(state => ({...state, error: "ALL fields are mandatory, please enter Project Name and Feed Link to create project."}))
return
}
rssFeedParser(formObj.link.trim())
.then((res) => {
axios.post(`${ServerPath}/projects/create`, {
name: formObj.name,
link: formObj.link
})
.then(response => {
if(response.data.error) {
setFormObj(state => ({...state, error: "Something went wrong. Please try again after some time."}))
} else {
fetchProjects()
toggleCreatePorjectModal(false)
}
})
.catch((err) => {
setFormObj(state => ({...state, error: err.msg}))
})
})
.catch((err) => {
setFormObj(state => ({...state, error: err.msg}))
})
}
return (
<div >
{/*Will Render Something based on above code*/}
</div>
)
}
Run Code Online (Sandbox Code Playgroud)
我只使用了一种 useState 来在一个对象中存储“名称”、“链接”、“错误”等属性。因为我想将 FormObj 和 validateLinkAndCreateProject 的逻辑保持在一起。所有三个属性仅使用一个 useEffect。因此,我认为最好将所有三个属性保留在 useState 中,而不是创建 3 个不同的 usestate。
But my manager, and my technical architect telling me to create 3 useState, one useState for each property,that is, separate useState for name, link and error. According to them, never create object inside useState like useState({name: "", link: "", error: ""}). I should always create separate useState for each property.
As per my understanding, in older react we used to have only one state which use to have 30 to 40 properties in one object. With introduction of React hooks, as per "separation of concern", we are suppose to separate related logic from rest of the code. Hence, we will end up 5 to 6 states having objects with 4 to 5 properties.
Note: Here "separation of concerns" means breaking class code in such way that dependent state + useEffect + useRef etc kept together. below is quote from React documentation.
Hooks let you split one component into smaller functions based on what pieces are related (such as setting up a subscription or fetching data), rather than forcing a split based on lifecycle methods.
I wanted to Am I missing anything??, Is it okay to create useState({name: "", link: "", error: ""}). or should I create separate state for each one of them?
小智 10
我意识到这是一个老问题,但如果其他人试图解决这个问题,我想说我已经用这种方式构建了一个完整的生产应用程序。每个页面(它是一个 next.js 应用程序)都使用一个 useState,并且其中是一个具有许多属性的对象。错误、表单数据、加载等。
如果您阅读了 React 文档,他们建议不要这样做,因为由于每次都会重新评估对象,可能会出现性能问题。即使如此,该应用程序运行速度仍然很快。我认为我们经常把事情变得过于复杂。当然,减速器会更好。但是,通过保持简单而无需陷入抽象复杂性的开发速度所带来的错误和性能问题比人们想象的要少得多。请记住,React 团队很聪明。他们不会让你陷入失败。如果它确实极大地阻碍了性能,并且它是像 useState 这样的基本事物,那么他们会竭尽全力阻止您做这样的事情。
顺便说一句,这个生产应用程序每周为数百名活跃用户提供订餐服务,我们没有收到任何投诉,只听到了好消息。
It\'s a judgement call, but in most cases, yes, use separate useState calls for each of those three pieces of state information (or use useReducer instead). That way, setting them is simple and straightfoward. E.g.:
const [name, setName] = useState("");\nconst onNameChange = e => setName(e.target.value);\nRun Code Online (Sandbox Code Playgroud)\n<input\n type="text"\n onChange={onNameChange}\n>\nRun Code Online (Sandbox Code Playgroud)\nClass-based components get a setState function that accepts partial state updates and merges them into the component\'s state, but that isn\'t how useState\'s setter works; it completely replaces the state item.\xc2\xb9 That means if you\'re using a compound state item as in your question, you have to include all of its parts in every call to the setter\xc2\xa0\xe2\x80\x94 which sets you up to accidentally use stale copies of the parts you\'re not intentionally updating:
<input\n type="text"\n onChange={onNameChange}\n>\nRun Code Online (Sandbox Code Playgroud)\nThe problem there is that the data in formObj can be out of date. You\'d have to use the callback form instead:
const [formObj, setFormObj] = useState({name: "", link: "", error: ""});\nconst onNameChange = ({target: {value}}) => setFormObj({...formObj, name: value}); // <== USUALLY WRONG\nRun Code Online (Sandbox Code Playgroud)\nThe other issue is that if you\'re using any of those pieces of state as dependencies in a useEffect/useMemo/useCallback/etc., it\'s easy to get that wrong too.
So yes, your manager and tech architect are likely correct, use individual useState calls (or useReducer). But, again, it\'s a judgement call; you could just always use the callback form of useFormObj.
Another option:
\nYou could create a hook for the form object with individual setters for the name, link, and error that accept either a string or an event, like this:
\n// A reusable utility function: if the argument is an object with a `target` property,\n// return `x.target.value`; otherwise, just return `x`.\nfunction unwrapValue(x) {\n if (typeof x === "object" && x.target) {\n x = x.target.value;\n }\n return x;\n}\n\n// Off-the-cuff, untested, just a sketch\nfunction useFormObj(initialFormObj = {name: "", link: "", error: ""}) {\n const [formObj, setFormObj] = useState(initialFormObj);\n const setters = useRef(null);\n if (!setters.current) {\n // Only true on first call\n setters.current = {\n setName(name) {\n name = unwrapValue(name);\n setFormObj(formObj => ({...formObj, name}));\n },\n setLink(link) {\n link = unwrapValue(link);\n setFormObj(formObj => ({...formObj, link}));\n },\n setError(error) {\n error = unwrapValue(error);\n setFormObj(formObj => ({...formObj, error}));\n },\n };\n }\n return [formObj, setters.current];\n}\nRun Code Online (Sandbox Code Playgroud)\nAnd then:
\nconst [formObj, setFormObj] = useState({name: "", link: "", error: ""});\nconst onNameChange = ({target: {value}}) => setFormObj(formObj => ({...formObj, name: value}));\nRun Code Online (Sandbox Code Playgroud)\n<input\n type="text"\n onChange={setName}\n>\nRun Code Online (Sandbox Code Playgroud)\nThat\'s handy when you need to use form objects in more than one component, or you just want to have smaller more easily-testable pieces.
\n\xc2\xb9 从文档中(您必须稍微向下滚动到“注意: ”):
\n\n\n笔记
\n\n
setState与类组件中的方法不同,useState它不会自动合并更新对象。您可以通过将函数更新器形式与对象扩展语法相结合来复制此行为:Run Code Online (Sandbox Code Playgroud)\nsetState(prevState => {\n // Object.assign would also work\n return {...prevState, ...updatedValues};\n});\n另一个选项是
\nuseReducer,它更适合管理包含多个子值的状态对象。
| 归档时间: |
|
| 查看次数: |
7081 次 |
| 最近记录: |