React Transition Group - 2

600 阅读1分钟

SwitchTransition

  • Based on the selected mode and the child's key which is the Transitin or CSSTransition component, theSeitchTransition makes a consistent transition between them.
  • If the out-in mode is selected, the SwitchTransition waits until the old child leaves ant then inserts a new child.
  • If the in-out mode is selected, the SwitchTransition inserts a new child first, waits for the new child to enter and then removes the old child.
import React from "react";
import { SwitchTransition, CSSTransition } from "react-transition-group";
import { Button, Form } from "react-bootstrap";
import "./styles.css";

const modes = ["out-in", "in-out"];

export default function App() {
  const [mode, setMode] = React.useState("out-in");
  const [state, setState] = React.useState(true);
  return (
    <>
      <div className="label">Mode:</div>
      <div className="modes">
        {modes.map(m => (
          <Form.Check
            key={m}
            custom
            inline
            label={m}
            id={`mode=msContentScript${m}`}
            type="radio"
            name="mode"
            checked={mode === m}
            value={m}
            onChange={event => {
              setMode(event.target.value);
            }}
          />
        ))}
      </div>
      <div className="main">
        <SwitchTransition mode={mode}>
          <CSSTransition
            key={state}
            addEndListener={(node, done) => {
              node.addEventListener("transitionend", done, false);
            }}
            classNames="fade"
          >
            <div className="button-container">
              <Button onClick={() => setState(state => !state)}>
                {state ? "Hello, world!" : "Goodbye, world!"}
              </Button>
            </div>
          </CSSTransition>
        </SwitchTransition>
      </div>
    </>
  );
}

Props:
mode
children


TransitionGroup

  • The component manages a set of transition components(<Transition> and <CSSTransition>)in a list, Like with the transition components.
  • Consider the example below. As items are removed or added to the TodoList the in prop is toggled automatically by the .
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import {
  Container,
  ListGroup,
  Button,
} from 'react-bootstrap';
import {
  CSSTransition,
  TransitionGroup,
} from 'react-transition-group';
import uuid from 'uuid';

import './styles.css';

function TodoList() {
  const [items, setItems] = useState([
    { id: uuid(), text: 'Buy eggs' },
    { id: uuid(), text: 'Pay bills' },
    { id: uuid(), text: 'Invite friends over' },
    { id: uuid(), text: 'Fix the TV' },
  ]);
  return (
    <Container style={{ marginTop: '2rem' }}>
      <ListGroup style={{ marginBottom: '1rem' }}>
        <TransitionGroup className="todo-list">
          {items.map(({ id, text }) => (
            <CSSTransition
              key={id}
              timeout={500}
              classNames="item"
            >
              <ListGroup.Item>
                <Button
                  className="remove-btn"
                  variant="danger"
                  size="sm"
                  onClick={() =>
                    setItems(items =>
                      items.filter(item => item.id !== id)
                    )
                  }
                >
                  &times;
                </Button>
                {text}
              </ListGroup.Item>
            </CSSTransition>
          ))}
        </TransitionGroup>
      </ListGroup>
      <Button
        onClick={() => {
          const text = prompt('Enter some text');
          if (text) {
            setItems(items => [
              ...items,
              { id: uuid(), text },
            ]);
          }
        }}
      >
        Add Item
      </Button>
    </Container>
  );
}

ReactDOM.render(
  <TodoList />,
  document.getElementById('root')
);

.remove-btn {
  margin-right: 0.5rem;
}

.item-enter {
  opacity: 0;
}
.item-enter-active {
  opacity: 1;
  transition: opacity 500ms ease-in;
}
.item-exit {
  opacity: 1;
}
.item-exit-active {
  opacity: 0;
  transition: opacity 500ms ease-in;
}

Props:
component
appear
enter
exit
childFactory


With React Router

 import "./packages/react-router-dom/examples/Animation/styles.css";

import React from "react";
import {
 TransitionGroup,
 CSSTransition
} from "react-transition-group";
import {
 BrowserRouter as Router,
 Switch,
 Route,
 Link,
 Redirect,
 useLocation,
 useParams
} from "react-router-dom";

export default function AnimationExample() {
 return (
   <Router>
     <Switch>
       <Route exact path="/">
         <Redirect to="/hsl/10/90/50" />
       </Route>
       <Route path="*">
         <AnimationApp />
       </Route>
     </Switch>
   </Router>
 );
}

function AnimationApp() {
 let location = useLocation();

 return (
   <div style={styles.fill}>
     <ul style={styles.nav}>
       <NavLink to="/hsl/10/90/50">Red</NavLink>
       <NavLink to="/hsl/120/100/40">Green</NavLink>
       <NavLink to="/rgb/33/150/243">Blue</NavLink>
       <NavLink to="/rgb/240/98/146">Pink</NavLink>
     </ul>

     <div style={styles.content}>
       <TransitionGroup>
         {/*
           This is no different than other usage of
           <CSSTransition>, just make sure to pass
           `location` to `Switch` so it can match
           the old location as it animates out.
         */}
         <CSSTransition
           key={location.key}
           classNames="fade"
           timeout={300}
         >
           <Switch location={location}>
             <Route path="/hsl/:h/:s/:l" children={<HSL />} />
             <Route path="/rgb/:r/:g/:b" children={<RGB />} />
           </Switch>
         </CSSTransition>
       </TransitionGroup>
     </div>
   </div>
 );
}

function NavLink(props) {
 return (
   <li style={styles.navItem}>
     <Link {...props} style={{ color: "inherit" }} />
   </li>
 );
}

function HSL() {
 let { h, s, l } = useParams();

 return (
   <div
     style={{
       ...styles.fill,
       ...styles.hsl,
       background: `hsl(${h}, ${s}%, ${l}%)`
     }}
   >
     hsl({h}, {s}%, {l}%)
   </div>
 );
}

function RGB() {
 let { r, g, b } = useParams();

 return (
   <div
     style={{
       ...styles.fill,
       ...styles.rgb,
       background: `rgb(${r}, ${g}, ${b})`
     }}
   >
     rgb({r}, {g}, {b})
   </div>
 );
}

const styles = {};

styles.fill = {
 position: "absolute",
 left: 0,
 right: 0,
 top: 0,
 bottom: 0
};

styles.content = {
 ...styles.fill,
 top: "40px",
 textAlign: "center"
};

styles.nav = {
 padding: 0,
 margin: 0,
 position: "absolute",
 top: 0,
 height: "40px",
 width: "100%",
 display: "flex"
};

styles.navItem = {
 textAlign: "center",
 flex: 1,
 listStyleType: "none",
 padding: "10px"
};

styles.hsl = {
 ...styles.fill,
 color: "white",
 paddingTop: "20px",
 fontSize: "30px"
};

styles.rgb = {
 ...styles.fill,
 color: "white",
 paddingTop: "20px",
 fontSize: "30px"
};