web-dev-qa-db-fra.com

React css transition ne fonctionne pas correctement

J'ai écrit une application React à l'aide de transitions CSS. Mais ces transitions ne fonctionnent pas correctement dans certains composants. Dans mon application , seuls les composants qui se déplacent vers le haut fonctionnent bien, ceux qui se déplacent vers le bas se déplaçant instantanément sans animation. (Je veux les deux mouvements avec animation.)

Voici le CSS que j'ai utilisé ici:

div.canvas {
    position: absolute;
    top: 90px;
    left: 60px;
    width: 640px;
    height: 480px;
    border: 1px solid #999;
    background: white;

}

div.canvas-rect {
    position: relative;
    margin-left: 20px;
    margin-top: 10px;
    height: 20px;
    background: green;

    transition: all 1s linear;
    -moz-transition: all 1s linear; /* Firefox 4 */
    -webkit-transition: all 1s linear; /* Safari 和 Chrome */
    -o-transition: all 1s linear; /* Opera */

}

MIS À JOUR:

J'ai également construit un projet codepen.io pour montrer le problème. Il a le code complet de ce projet de démonstration.

J'ai essayé d'ajouter une entrée de journal aux méthodes componentDidUpdate, componentDidMount et componentWillUnmount pour indiquer si ces composants sont recréés ou mis à jour, cela signifie qu'ils sont tous mis à jour (pas recréés ou supprimés) chaque seconde.

19
cmal

Eh bien, après avoir commencé une prime parce que j'ai aussi ce problème, j'ai finalement trouvé ce qui semblait être le problème.

Lorsque vous utilisez une position absolue (ou relative, comme dans votre cas), si vous refaites la totalité de la liste à chaque fois, React réorganisera les éléments dans le DOM (comme vous l'avez dit, les éléments ne sont pas recréés, mais simplement mis à jour). Mais cela crée un problème avec les transitions ... apparemment, si vous déplacez un élément alors que la transition est en cours, vous finissez par couper l'animation.

Ainsi, dans les cas où vous souhaitez utiliser position absolue, le concept clé consiste à rendre les conteneurs de vos éléments une seule fois (dans ce cas, il suffit de div) et à ne modifier que le contenu interne en fonction du nouvel ordre. Si vous avez besoin d'ajouter plus d'éléments, ajoutez-les simplement à la fin.

J'ai modifié votre code codé pour qu'il reflète ce que je dis. Mon exemple est très stupide car je viens de créer 4 div ad-hoc, mais cela illustre bien l’idée: créez autant de conteneurs que vous le souhaitez, mais n’utilisez PAS de carte les recréant à chaque fois, sinon vos transitions seront coupées.

https://codepen.io/damianmr/pen/boEmmy?editors=0110

const ArrList = ({
  arr
}) => {
  return (
    <div style={{position: 'relative'}}>
      <div className={`element element-${arr[0]} index-${arr[0]}`}>{arr[0]}</div>
      <div className={`element element-${arr[1]} index-${arr[1]}`}>{arr[1]}</div>  
      <div className={`element element-${arr[2]} index-${arr[2]}`}>{arr[2]}</div>  
      <div className={`element element-${arr[3]} index-${arr[3]}`}>{arr[3]}</div>  
    </div>
  );
}

Le problème est donc essentiellement de savoir comment créer une liste statique de conteneurs et comment parcourir cette liste afin que le premier conteneur restitue le premier élément de vos données, le second le deuxième élément, etc.

J'espère que ça aide, ce problème me rendait fou aussi! :)

15
damianmr

Si vous supprimez l'élément du DOM virtuel, la réaction mettra à jour son contenu, vous ne verrez donc pas les animations. Ce que vous pouvez faire est d’utiliser soit react-transition-group OR, indiquez à votre application d’attendre x ms avant de mettre à jour le dom une fois que l’événement est appelé OR. au lieu de le supprimer complètement du DOM.

2
Iruss

Vous pouvez piéger React en utilisant index comme clé. Si vous pensez à el, et index en tant que position de départ (index) et fin, (el), l'élément est passé à l'ancienne position de fin à la fin de la transition et lorsqu'il est présent, il est remplacé par le nouveau début. position et (index) est commuté pour correspondre à la nouvelle configuration. En effet, lorsque vous définissez key dans un élément de react, le DOM virtuel l'interprétera toujours car il s'agit du même élément. Et pour le plaisir, vous avez raison de définir Index comme "id" en général.

J'ai fait un exemple de travail uniquement en commutant index/el (et en définissant la position de l'élément en absolu).

const {combineReducers, createStore} = Redux;
const { Provider, connect } = ReactRedux;

const ArrList = ({
  arr
}) => (
  <div>{
  arr.map((el, index)=>
          <div
            key={""+index}
            className={`element element-${el}` + ` index-${el}`}
            >
            {el}
          </div>) }
  </div>
)
      
const mapStateToArrList = (state) => {
  return {
    arr: state.appReducer.arr
  }
};

const App = connect(mapStateToArrList, null)(ArrList);

const initialState = {
  arr: [1, 2, 3, 4]
}

const appReducer = (state = initialState, action) => {
  switch(action.type) {
    case "tick":
      return {
        ...state,
        arr: _.shuffle(state.arr)
      }
    default:
      return state
   }
}

const reducer = combineReducers({
  appReducer
})


const store = createStore(reducer)

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

const dispatcher = () => {
  store.dispatch({
     type: "tick"
  })
  setTimeout(dispatcher, 1000)
}

dispatcher()
.element {
    position: absolute;
    height: 20px;
    background: green;
    margin-left: 20px;
    margin-top: 20px;

    text-align: right;
    color: white;
    line-height: 20px;

    transition: all 1s ease-in;
    -moz-transition: all 1s ease-in; /* Firefox 4 */
    -webkit-transition: all 1s ease-in; /* Safari 和 Chrome */
    -o-transition: all 1s ease-in; /* Opera */

}

.element-1 {
    width: 20px;
}

.element-2 {
    width: 40px;
}

.element-3 {
    width: 60px;
}

.element-4 {
    width: 80px;
}

.index-1 {
  top: 20px;
}

.index-2 {
  top: 40px;
}

.index-3 {
  top: 60px;
}

.index-4 {
  top: 80px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.7.2/redux.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.6/react-redux.js"></script>

<div id="root"></div>

2
LPL

Vous avez recréé des éléments DOM à chaque fois.
Vous devez définir la valeur de clé de collecte . J'ai changé votre valeur de clé '' + el en '' + index.

<div key={'' + index} className={'element element-' + el + ' index-' + index} >

Il suffit de changer les propriétés css uniquement :)

1
panghea