{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreib67uattnmpovnmcejyijxrzlinyn7cb2cdjyylcoj3cywgxn2hle",
    "uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3moraklznhoe2"
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreigbyan6h6gz2ngior7otw4ezabsan5qrbem64bt2hzjajac6nvhku"
    },
    "mimeType": "image/webp",
    "size": 108386
  },
  "path": "/kkr0423/reactjs-usestate-antipatterns-58i9",
  "publishedAt": "2026-06-21T01:06:41.000Z",
  "site": "https://dev.to",
  "tags": [
    "webdev",
    "programming",
    "react",
    "frontend"
  ],
  "textContent": "**1. Consider grouping related conditions together**\n\n  * Before\n\n\n\n\n      const [x, setX] = useState(0);\n      const [y, setY] = useState(0);\n\n      const handlePointerMove = (e) => {\n        setX(e.clientX);\n        setY(e.clientY);\n      };\n      return (\n          <div\n            onPointerMove={handlePointerMove}\n            style={{\n              width: \"100vw\",\n              height: \"100vh\",\n            }}\n          />\n      );\n\n\n  * After\n\n\n\n\n     const [position, setPosition] = useState({ x: 0, y: 0 });\n\n     const handlePointerMove = (e) => {\n        setPosition({\n          x: e.clientX,\n          y: e.clientY,\n        });\n      };\n      return (...\n      );\n\n\n\n  * Before\n\n\n\n\n    const [userName, setUserName] = useState(\"\");\n    const [userAge, setUserAge] = useState(0);\n\n\n  * After\n\n\n\n\n    const [userInfo, setUserInfo] = useState({name:\"\",age:0});\n\n\n**2. Avoid declaring conflicting states**\n\n  * Before\n\n\n\n\n    export default function Form() {\n      const [text, setText] = useState('');\n      const [isSubmitting, setSubmitting] = useState(false);\n      const [isSubmit, setIsSubmit] = useState(false);\n\n      async function handleSubmit(e) {\n        e.preventDefault();\n        isSubmitting(true);\n        await sendMessage(text);\n        isSubmitting(false);\n        setIsSubmit(true);\n      }\n\n      if (isSubmit) {\n        return <h1>I appreciate</h1>\n      }\n\n      function sendMessage(text) {\n        return new Promise(resolve => {\n        setTimeout(resolve, 2000);\n       });\n      }\n\n      return (\n        <form onSubmit={handleSubmit}>\n          <textarea\n            disabled={isSending}\n            value={text}\n            onChange={e => setText(e.target.value)}\n          />\n          <br />\n          <button\n            disabled={isSending}\n            type=\"submit\"\n          >\n            Submit\n          </button>\n          {isSubmitting && <p>Submitting...</p>}\n        </form>\n      );\n    }\n\n\n  * After\n\n\n\n\n    export default function Form() {\n      const [text, setText] = useState('');\n      const [status, setStatus] = useState('TYPING');\n\n      async function handleSubmit(e) {\n        e.preventDefault();\n        setStatus('SUBMITTING');\n        await sendMessage(text);\n        setStatus('SUBMITTED');\n      }\n\n      const isSending = status === 'SUBMITTING';\n      const isSent = status === 'SUBMITTED';\n\n      return (...\n      );\n    }\n\n\n`isSubmit` and `isSubmitting` are conflicting and make it difficult to handle these states as it gets complex.\nYou have to group them into a single state.\n\n**3. Avoid redundant use**\n\n\n\n    export default function Form() {\n      const [firstName, setFirstName] = useState('');\n      const [lastName, setLastName] = useState('');\n      const [fullName, setFullName] = useState('');\n\n      function handleFirstNameChange(e) {\n        setFirstName(e.target.value);\n        setFullName(e.target.value + ' ' + lastName);\n      }\n\n      function handleLastNameChange(e) {\n        setLastName(e.target.value);\n        setFullName(firstName + ' ' + e.target.value);\n      }\n\n      return (\n        <>\n          <label>\n            First name:\n            <input\n          name=\"firstName\"\n              value={firstName}\n              onChange={handleFirstNameChange}\n            />\n          </label>\n          <label>\n            Last name:\n            <input\n          name=\"lastName\"\n              value={lastName}\n              onChange={handleLastNameChange}\n            />\n          </label>\n          <p>\n            FullName: <span>{fullName}</span>\n          </p>\n        </>\n      );\n    }\n\n\n\nThe `fullName` can be calculated when rendering by `firstName` + `lastName`.\n\n\n\n      const [userName, setUserName] = useState({ firstName: \"\", lastName: \"\" });\n      const fullName = userName.firstName + \" \" + userName.lastName;\n\n      const handleUserNameChange = (e) => {\n        setUserName({ ...userName, [e.target.name]: e.target.value });\n      };\n\n\n\nAnd props should not be held in the state.\n\n\n\n    function Text({ children, color }) {\n      const [textColor] = useState(color);\n\n      return <h1 style={{ color: textColor }}>{children}</h1>;\n    }\n\n    export default function Example() {\n      const [color, setColor] = useState(\"red\");\n\n      return (\n        <div>\n          <p>\n            Select Color\n            <select value={color} onChange={(e) => setColor(e.target.value)}>\n              <option value=\"red\">Red</option>\n              <option value=\"blue\">Blue</option>\n              <option value=\"green\">Green</option>\n            </select>\n          </p>\n          <Text color={color}>Color will be changed</Text>\n        </div>\n      );\n    }\n\n\n\nThe color seems to change at a glance, but doesn't change.\nBecause `useState` is initialized when first rendering.\n\n  * Fixed\n\n\n\n\n    function Text({ children, color }) {\n      const textColor = color;\n\n      return <h1 style={{ color: textColor }}>{children}</h1>;\n    }\n\n\n\n**4. Avoid declaring the same state multiple times**\n\n\n\n    const initialItems = [\n      { id: 1, title: \"taskA\" },\n      { id: 2, title: \"taskB\" },\n      { id: 3, title: \"taskC\" },\n    ];\n\n    export default function TaskList() {\n      const [tasks, setTasks] = useState(initialItems);\n      const [selectedTask, setSelectedTask] = useState(tasks[0]);\n\n      function handleTaskChange(id, e) {\n        setTasks(tasks.map((task) => (task.id === id ? { ...task, title: e.target.value } : task)));\n        setSelectedTask((task) => (task.id === id ? { ...task, title: e.target.value } : task));\n      }\n\n      return (\n        <>\n          <h2>Task List</h2>\n          <ul>\n            {tasks.map((task, index) => (\n              <li key={task.id}>\n                <input\n                  value={task.title}\n                  onChange={(e) => {\n                    handleTaskChange(task.id, e);\n                  }}\n                />\n                <button\n                  onClick={() => {\n                    setSelectedTask(task);\n                  }}\n                >\n                  Select\n                </button>\n              </li>\n            ))}\n          </ul>\n          <p>Today's task {selectedTask.title}</p>\n        </>\n      );\n    }\n\n\n\nThe `task` and the `selectedTask` handle the same data.\nWhen you edit the task, you have to update `selectedTask`.\n\nSo, fix the codebase to calculate the `selectedTask` by id\n\n\n\n    function TaskList() {\n      const [tasks, setTasks] = useState(initialItems);\n      const [selectedTaskId, setSelectedTaskId] = useState(0);\n\n      function handleTaskChange(id, e) {\n        setTasks(tasks.map((task) => (task.id === id ? { ...task, title: e.target.value } : task)));\n      }\n\n      const selectedTask = tasks.find((task) => task.id === selectedTaskId);\n\n      return (\n        <>\n          <h2>Task List</h2>\n          <ul>\n            {tasks.map((task) => (\n              <li key={task.id}>\n                <input\n                  value={task.title}\n                  onChange={(e) => {\n                    handleTaskChange(task.id, e);\n                  }}\n                />\n                <button\n                  onClick={() => {\n                    setSelectedTaskId(task.id);\n                  }}\n                >\n                  Select\n                </button>\n              </li>\n            ))}\n          </ul>\n          <p>Today's Task {selectedTask.title}</p>\n        </>\n      );\n    }\n\n",
  "title": "React.js ~useState Antipatterns~"
}