While I appreciate the functional usage of state, this type of magical behavior worries me a bit. Wasn't more straightforward semantics possible (even if the syntax wasn't similarly straightforward)?
While I appreciate the functional usage of state, this type of magical behavior worries me a bit. Wasn't more straightforward semantics possible (even if the syntax wasn't similarly straightforward)?
While it may _look_ nice to be able to just call `useEffect` and have it infer the rest, it just ends up masking the flow of a hidden parameter into that component, and convolutes the user's understanding of what React is actually doing.
With `useEffect`, I have no idea what is actually happening here, and I've tried re-reading it a few times.
As for `useEffect`: think about the kind of logic you'd put in `componentDidMount`, `componentDidUpdate`, and `componentWillUnmount`. In CDM, we set up side effects, in CDU, we update those side effects if needed (based on the props, state, and context) and in CWU, we clean up those side effects. If we squint a little, though, we're really only doing two actual operations in those three steps:
didMount: perform side effect A based on props/state/context didUpdate: clean up side effect A, then perform side effect B based on props/state/context didUpdate (again): clean up side effect B, then perform side effect C based on props/state/context willUnmount: clean up side effect C
So the idea here is:
const [name, setName] = useState("world");
function modifyTitle() {
document.title = "Hello, " + name + "!";
return restoreTitle;
}
function restoreTitle() {
document.title = "Untitled";
}
useEffect(modifyTitle);
When this component is rendered, it'll run `modifyTitle` on the first pass, and store its return value (`restoreTitle`) for later. When it's rendered the _next_ time, it'll call `restoreTitle` first and then `modifyTitle` again... which itself returns a new "cleanup function".So we basically have the same sequence of calls as this is mounted/updated/unmounted:
perform side effect A cleanup side effect A, then perform side effect B cleanup side effect B, then perform side effect C cleanup side effect C
The only difference is we never told React _when_ to perform these steps, just _that it should_ perform them at the appropriate time.
const [foo, setFoo] = useState("abc");
const [bar, setBar] = useState("123");
...is functionally the same thing as const [bar, setBar] = useState("123");
const [foo, setFoo] = useState("abc");
The feature is _declarative_ in the same way element rendering is declarative.Edit: And yes, slight concern of course, it's the got some rough semantic equivalents to a thread-local in Java, albeit in Java the danger exists downstream, this danger is only exhibited during initialization it seems.
Tagged template literals already give us something of a callsite, since the template strings object is cached per callsite. You could do something ugly and use that to associate state:
const state = useState``(); TypeError: Cannot define property foo, object is not extensible
Cool idea though > f = l => l
[Function: f]
> f`hi` === f`hi`
trueNote they also say:
> We provide a linter plugin to enforce these rules automatically.
Makes me feel a little better.
Like, if I have two state variables, pass in a name for both, instead of relying on the order being the same.