React-spring: Unable to transition with function as child

Created on 12 Jul 2018  路  4Comments  路  Source: pmndrs/react-spring

I'm trying to implement a transition between different divs. I can get it to work if I style my code in the same fashion as: https://codesandbox.io/embed/yj52v5689
(i.e. indexing off an array and providing a style => return component for each item)

However, if I make the following change, it no longer animates

-{pages[this.state.index]}
+{s => pages[this.state.index](s)}

See: https://codesandbox.io/s/xp8qo6mk4q

Does it have to do with how it interprets the key as mentioned here: https://github.com/drcmda/react-spring/issues/113#issuecomment-396674860?

I'd appreciate a fresh pair of eyes, I'm baffled.

Most helpful comment

Well the easiest would be if you had three functions that could serve as keys on their own (like in the original example). If you need to create it dynamically then you need keys. Keys are regular React keys, they can be anything from numbers, strings, components, anything that helps React recognize and track what you put in there.

Sure it probably could be easier, for instance:

import * as components from './components'

render() {
    const key = this.state.key
    const Component = components[key]
    return (
        <Transition
            native
            keys={key}
            from={{ opacity: 0, height: 0 }}
            enter={{ opacity: 1, height: "auto" }}
            leave={{ opacity: 0, height: 0 }}>
            {style => <Component style={style} />}
        </Transition>
    )
}

Where ./components just exports a bunch of components

export class A extends Component { ... }
export class B extends Component { ... }
export class C extends Component { ... }

But the way you build that is up to you, Transition just needs to know how to track its elements.

All 4 comments

@cklab that's correct, adding

keys={this.state.index}

would make it work. When you don't specify keys Transition has to use the functions you supply as such, but in your case you create a new function every time on render, that makes it impossible for React to know if elements can be re-used, it will start mounting and unmounting components effectively interrupting transitions work.

Hmm. Ok. Having verification on that is helpful. I have one more follow up on this use case.

Assuming I have 3 components to switch between, like in the example; and instead of an index, I evaluate a series of state properties to determine which component to render,

(A) would it be fair to say that I must first compress them down to a key (that I can use for the keys prop) rather then directly to a component?
(B) Is the below a reasonable implementation?
(C) Is there a similar example documented?

    getKey = () => {
        const { a, b, c} = this.state;
        if (a) return "a";
        if (b) return "b";
        if (c) return "c";
    }

    getComponent = (key) => style => {
        switch (key) {
            case "a": return <A/>
            case "b": return <B/>
            case "c": return <C/>
        }
    }

    render() {
        const key = this.getKey();
        return (
            <Transition
                native
                keys={key}
                from={{ opacity: 0, height: 0 }}
                enter={{ opacity: 1, height: "auto" }}
                leave={{ opacity: 0, height: 0 }}>
                { this.getComponent(key) }

            </Transition>
        )
    }

I feel like I'm doing some unnatural for some reason..

Well the easiest would be if you had three functions that could serve as keys on their own (like in the original example). If you need to create it dynamically then you need keys. Keys are regular React keys, they can be anything from numbers, strings, components, anything that helps React recognize and track what you put in there.

Sure it probably could be easier, for instance:

import * as components from './components'

render() {
    const key = this.state.key
    const Component = components[key]
    return (
        <Transition
            native
            keys={key}
            from={{ opacity: 0, height: 0 }}
            enter={{ opacity: 1, height: "auto" }}
            leave={{ opacity: 0, height: 0 }}>
            {style => <Component style={style} />}
        </Transition>
    )
}

Where ./components just exports a bunch of components

export class A extends Component { ... }
export class B extends Component { ... }
export class C extends Component { ... }

But the way you build that is up to you, Transition just needs to know how to track its elements.

Thanks for the clarifying this for me. Sorry for having used this space as a Q&A :sweat_smile:

Was this page helpful?
0 / 5 - 0 ratings