Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ryan-williams/nextjs-state-issue
Repro of buggy Next.js / React behavior involving initial state values not matching between server and client
https://github.com/ryan-williams/nextjs-state-issue
Last synced: about 2 months ago
JSON representation
Repro of buggy Next.js / React behavior involving initial state values not matching between server and client
- Host: GitHub
- URL: https://github.com/ryan-williams/nextjs-state-issue
- Owner: ryan-williams
- Created: 2023-01-04T15:08:08.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2023-01-04T15:38:36.000Z (almost 2 years ago)
- Last Synced: 2024-10-20T07:45:31.091Z (3 months ago)
- Language: JavaScript
- Size: 1.29 MB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# nextjs-state-issue
Examining a bug(?) involving populating React state from URL query params- [Repro](#repro)
- [Boot `next dev` server ✅](#boot)
- [View 127.0.0.1:3000 ✅](#view-default)
- [Now try 127.0.0.1:3000?v=D ❌](#view-D)
- [Click "A" ❌](#view-A)
- [Discussion](#discussion)
- [Issue is not specific to the `disabled` attribute](#bold)### Boot `next dev` server ✅
```bash
next dev
```[`index.js`](./pages/index.js) just parses the URL query string for a "v" param, which is used to initialize one of 5 buttons ("C" by default):
```javascript
import {useRouter} from "next/router"
import {useState} from "react";export const pathnameRegex = /[^?#]+/u
export default function Home() {
const searchStr = useRouter().asPath.replace(pathnameRegex, '')
const searchParams = new URLSearchParams(searchStr)
const initialValue = searchParams.get('v') || "C"
const [ value, setValue ] = useState(initialValue)
return (
{
["A", "B", "C", "D", "E"].map(v => {
const disabled = v === value
console.log(`v: ${v}, value: ${value}, disabled: ${disabled}`)
return setValue(v)} />
})
}
)
}
```### View [127.0.0.1:3000](http://127.0.0.1:3000) ✅
```bash
open http://127.0.0.1:3000
```
Page renders without error, "C" is "active" (disabled) by default:![](./screenshots/C.png)
So far, so good.
### Now try [127.0.0.1:3000?v=D](http://127.0.0.1:3000?v=D) ❌
![](./screenshots/D.png)
Several problems are visible:
- "C" is disabled (instead of "D")
- `console.log`s imply that "D" should be disabled, and "C" should not be
- Clicking "D" has no effect (something thinks it's already disabled)
- There's a console error about client and server "disabled" attributes not agreeing![](./screenshots/AC.png)
- "A" and "C" are both disabled
- There's no way to un-disable "C"; it is stuck due to having been default during server render
- `console.log`s imply only "A" should be disabled### Issue is not specific to the `disabled` attribute
At first I thought this might have to do with the `disabled` attribute being a boolean whose value is inferred from the presence or absence of the attribute (i.e. `` as opposed to ``).However, the issue occurs if the "active" button is styled with e.g. `font-weight: [bold|normal]` instead of toggling `disabled` (see [`bold` branch](https://github.com/ryan-williams/nextjs-state-issue/blob/bold/pages/index.js#L14-L16)):
```diff
- const disabled = v === value
- console.log(`v: ${v}, value: ${value}, disabled: ${disabled}`)
- return setVal>
+ const active = v === value
+ console.log(`v: ${v}, value: ${value}, active: ${active}`)
+ return
```![](./screenshots/AC-bold.png)
- Page loads with "C" bolded, though "D" is supposed to be
- Clicking "A" results in "A" and "C" both bolded, though only "A" is supposed to be
- One difference from the `disabled` example is that you can click "C" here, and it resets the page to a consistent state:
- "C" is understood to be the only "active" button (in the UI as well as `console.log`s)
- Subsequent button clicks work as expected