admin管理员组

文章数量:1430000

I have a background layer element defined in JSX which has set display:none intially:

<div id="naviBG" style={naviBGStyleClone} role="button" onClick={this.onCloseClicked} />

Style:

const naviBGStyle = {
  display: 'none',
  opacity: 0,
  transition: 'opacity 0.4s ease',
};

When clicked, I want the layer to smoothly disappear or re-appear using the transition defined in css. In render() I check if the element should be shown or hidden:

render()

const naviBGStyleClone = Object.assign({}, naviBGStyle);
if (this.props.status === 'closed') {
  naviBGStyleClone.display = 'none';
  naviBGStyleClone.opacity = 0;
} else {
  naviBGStyleClone.display = 'block';
  naviBGStyleClone.opacity = 1;
}

return (
    <div id="naviBG" style={naviBGStyleClone} role="button" onClick={this.onCloseClicked} />
);

Now, this kinda works as the element will be shown/hidden but it pops in without the transition animation set on opacity.

Normally I would then use something like requestAnimationFrame to work around this like so:

render() with raf:

const naviBGStyleClone = Object.assign({}, naviBGStyle);
if (this.props.status === 'closed') {
  naviBGStyleClone.display = 'none';
  if (typeof window !== 'undefined') {
    window.requestAnimationFrame(() => {
      naviBGStyleClone.opacity = 0;
    });
  }
} else {
  naviBGStyleClone.display = 'block';
  if (typeof window !== 'undefined') {
    window.requestAnimationFrame(() => {
      naviBGStyleClone.opacity = 1;
    });
  }
}

return (
    <div id="naviBG" style={naviBGStyleClone} role="button" onClick={this.onCloseClicked} />
);

But this won't work in react as it would cause the style to be modified after render() has already finished.

So, what's the correct way to do this in React?

I have a background layer element defined in JSX which has set display:none intially:

<div id="naviBG" style={naviBGStyleClone} role="button" onClick={this.onCloseClicked} />

Style:

const naviBGStyle = {
  display: 'none',
  opacity: 0,
  transition: 'opacity 0.4s ease',
};

When clicked, I want the layer to smoothly disappear or re-appear using the transition defined in css. In render() I check if the element should be shown or hidden:

render()

const naviBGStyleClone = Object.assign({}, naviBGStyle);
if (this.props.status === 'closed') {
  naviBGStyleClone.display = 'none';
  naviBGStyleClone.opacity = 0;
} else {
  naviBGStyleClone.display = 'block';
  naviBGStyleClone.opacity = 1;
}

return (
    <div id="naviBG" style={naviBGStyleClone} role="button" onClick={this.onCloseClicked} />
);

Now, this kinda works as the element will be shown/hidden but it pops in without the transition animation set on opacity.

Normally I would then use something like requestAnimationFrame to work around this like so:

render() with raf:

const naviBGStyleClone = Object.assign({}, naviBGStyle);
if (this.props.status === 'closed') {
  naviBGStyleClone.display = 'none';
  if (typeof window !== 'undefined') {
    window.requestAnimationFrame(() => {
      naviBGStyleClone.opacity = 0;
    });
  }
} else {
  naviBGStyleClone.display = 'block';
  if (typeof window !== 'undefined') {
    window.requestAnimationFrame(() => {
      naviBGStyleClone.opacity = 1;
    });
  }
}

return (
    <div id="naviBG" style={naviBGStyleClone} role="button" onClick={this.onCloseClicked} />
);

But this won't work in react as it would cause the style to be modified after render() has already finished.

So, what's the correct way to do this in React?

Share Improve this question asked Jun 6, 2017 at 14:02 Timo ErnstTimo Ernst 16k25 gold badges115 silver badges174 bronze badges 6
  • the most mon way to do this is doing it in two quick steps. set the display to block then on the next loop change the opacity. Is display block even a requirement though? what about changing the zindex instead? – azium Commented Jun 6, 2017 at 14:25
  • Yeah, I think it would be nice if the element pletely disappears from the render tree using display:none. What do you mean by "next loop"? – Timo Ernst Commented Jun 6, 2017 at 17:17
  • Next cycle of the event loop. If you trigger a css transition on an element with display none then the transition doesn't occur. if you set it to block then on the very next round of the event loop trigger the transition then it will happen. This is true with or without react. I can write up an answer with some examples if you want. My above suggestion is not the only way – azium Commented Jun 6, 2017 at 18:10
  • @azium That's why I used requestAnimationFrame - Doesn't work – Timo Ernst Commented Jun 6, 2017 at 18:52
  • requestAnimationFrame can be used, just not the way you have it. I'll write up an answer with some working examples – azium Commented Jun 6, 2017 at 18:57
 |  Show 1 more ment

1 Answer 1

Reset to default 4

Because transitions don't trigger on items that are hidden via display: none, you can call setState twice in a row, once to trigger the display change then again to trigger the opacity change, and the same in the reverse order to make it fade out then hidden.

class App extends React.Component {
  state = { display: 'none', opacity: 0 }

  toggle = () => {
    if (this.state.display === 'none') {
      this.setState({ display: 'block' })
      setTimeout(() =>
        this.setState({ opacity: 1 }), 10 // something very short
      )
    }
    if (this.state.display === 'block') {
      this.setState({ opacity: 0 })
      setTimeout(() =>
        this.setState({ display: 'none' }), 300 // same as transition time
      )
    }
  }

  render() {
    return (
      <div>
        <button onClick={this.toggle}>toggle</button>        
        <div 
          style={{ 
            transition: 'opacity 0.3s ease',
            opacity: this.state.opacity,
            display: this.state.display
          }} 
        />
      </div>
    )
  }
}

Example on codepen

I would also encourage you to look at React Motion for handling more intricate transitions like you might do with requestAnimationFrame

https://github./chenglou/react-motion

本文标签: javascriptHow to set displayblock and transition opacity at the same time in ReactStack Overflow