key
is pretty much crucial for state perservation in React. As of React 0.13 it can't do the following things:
- Clone state
<Comp key={1} /><Comp key={1} />
- Preserve component state across different parents:
// first render
<div><Comp key={1} /></div>
// second render, state destroyed
<span><Comp key={1} /></span>
- More generally, teleport state to another subtree completely:
// render of myComp1
<Comp key={uuid} />
// next render, myComp2
<Comp key={uuid} />
The reason I want these is to unlock some insane tricks, e.g.
- Teleport a half-done animation to another place, i.e. animated transition across views (easily solvable otherwise).
- A generalized version of frosted glass effect.
- Other similar logic, e.g. drag and drop component where a stateful component is transported somewhere else.
But I dislike key for a few reasons, one being that it's basically a user-generated hash, and that's unreliable and doesn't scale: for example, that duplicate component trick is risky, as it's not clear whether we really wanted <Comp key={1} /><Comp key={1} />
or if we accidentally did a key collision.
The (only?) other used alternative I've seen for key is cursors. But I've repeatedly heard that while these solve the problem (?), they're a bit tedius to work with. Is this true? Please leave a comment if you have any experience regarding this. The solution doesn't need reactive updates, or easier state propagation, or any of the nice extras; it just needs to solve the above few cases.
Not sure how I feel about this, but to avoid clashes, you can forbid the user to define custom keys.
Consider an opaque
key
that is created byReact.createKey()
.It can return an object like
{ isReactNewStyleKey: true, key: '... some random id ...' }
on every invocation.Because the new-style key is opaque to user, they can't generate a bad key by accident.
Every
key
created bycreateKey
is unique.If keys is a string, React just falls back to the old algorithm.
To teleport the state to another component, one could hold the key in some parent component, and transfer it as a prop:
This could also use the context:
It's probably crazy but hard to say until you build some real code with it. Anyway, the only real change from what you suggested is the opaqueness and, thus, the need to store the key.
Solved problems:
createKey(this)
argument) unmounts, the state is destroyed.