Home > front end >  How does react decide to replace vs update a component?
How does react decide to replace vs update a component?

Time:05-29

The following code

function Baz({on}) {
  const rect1 = <rect x='10' y='10' fill='red' width='10' height='10' />
  const rect2 = <rect x='80' y='10' fill='red' width='10' height='10' />
  const Rect3 = () => <rect x='10' y='80' fill='red' width='10' height='10' />
  const Rect4 = () => <rect x='80' y='80' fill='red' width='10' height='10' />
  return (
    <svg viewBox="0 0 100 100">
      { on ? rect1 : rect2 }
      { on ? <Rect3 /> : <Rect4 /> }
    </svg>
  );
}

will animate the transition from rect1 to rect2 (when css transitions are turned on) but not the transition from Rect3 to Rect4.

Why is this and is there any way to work around it?

A jsfiddle which shows what I mean: https://jsfiddle.net/2jLtn39z/

CodePudding user response:

I guess the first one update because you are changing the jsx elements, as opposed to the second one where you are replacing the component with another one.

CodePudding user response:

Thanks to some helpful answers I found a solution. Changing the <Rect3 /> (which is mounting Rect3 as a Component) to { Rect3() } (which returns the jsx elements and inserts them into the parent component, not creating any new components) makes the animation work. This also works with svgs imported as ReactComponents but since the imported svg is a class-component not a functional component you need to call it's render method instead.

An updated fiddle with the solution: https://jsfiddle.net/Ld6e0zyj/

const useState = React.useState
function Svg() {
  const [on, setOn] = useState(true);
  const toggle = () => setOn(on => !on);
  const rect1 = <rect x='10' y='10' fill='red' width='10' height='10' />;
  const rect2 = <rect x='80' y='10' fill='red' width='10' height='10' />;
  const Rect3 = () => <rect x='10' y='80' fill='red' width='10' height='10' />;
  class Rect4 extends React.Component {
    render() {
      return <rect x='80' y='80' fill='red' width='10' height='10' />;
    }
  }
  return (
    <div>
      <svg viewBox="0 0 100 100">
        { on ? rect1 : rect2 }
        { on ? Rect3() : new Rect4().render() }
      </svg>
      <button onClick={toggle}> Toggle </button>
    </div>
  );
}
ReactDOM.render(<Svg />, document.querySelector("#app"))
  • Related