Skip to content

Instantly share code, notes, and snippets.

@chenglou
Last active April 5, 2021 19:15
Show Gist options
  • Save chenglou/34b155691a6f58091953 to your computer and use it in GitHub Desktop.
Save chenglou/34b155691a6f58091953 to your computer and use it in GitHub Desktop.
Better feature for React key

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.

@threepointone
Copy link

I'm currently obsessed with 'render callbacks'/'children as a function' to represent values changing over time. I made 2 small animation libs to test it out, and they're quite fun (imo) - react-springs / react-ease. I also had a small discussion regarding this on react/3398

Pertinent to this discussion -

  • I can now abstract out animation 'state' with a (Spring/Ease/etc) component that's easy to move up in the hierarchy, if need be. this makes it easier to move the target element across trees, as long as the 'animation component' is a parent to both. (than, say, adding a mixin and marking this.state.name1, .name2 as 'special', etc).
  • keys for elements aren't tied to my animation requirements

@chenglou
Copy link
Author

@threepointone: oh man, we basically did the same thing for the spring library. Here's mine: https://github.com/chenglou/react-animation

I've been trying to solve the animation problem for the longest time and I think the children as function piece helped in cracking it. I'll be talking about it during React-Europe actually. But for now I wanted it to stay relatively hidden so that I could polish and release it.

@dantman
Copy link

dantman commented Sep 27, 2015

I experimented with writing a mixin for a different syntax for these.

React.createClass({
  mixins: [ReusableBlockMixin],
  // ...
  render() {
    var {Block} = this,
        {singleColumn} = this.state,
        nav = <Block tag="nav">
          ...
        },
        main = <Block tag="main">
          ...
        };

    return singleColumn
      ? <div>
        {nav}
        {main}
      </div>
      :  <div>
        <div className="nav">{nav}</div>
        <div className="main">{main}</div>
      </div>;
    }
  }
});

The Block component is individual to components using this api. My use of tag rather than key was inspired by the Android fragments api. Block's tagged children are scoped to the component that owns Block. So when the component is unmounted then the tagged blocks are unmounted. Otherwise when a tagged Block is unmounted the rendered children are just detached and linger around. If another Block with the same tag appears then it attaches the children rendered for that tag.

@camwest
Copy link

camwest commented Oct 21, 2017

Now that React 16 is out has anyone put any more thought into this issue?

@dantman
Copy link

dantman commented Mar 12, 2018

I've opened an RFC with a proposal for an API that allows for reparenting:

reactjs/rfcs#34

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment