We are going to make a Todo list with some animations:
- First, let's create our Todo component:
import React, { Component } from 'react';
import uuidv4 from 'uuid/v4';
import List from './List';
import './Todo.css';
class Todo extends Component {
constructor() {
super();
// Initial state...
this.state = {
task: '',
items: []
};
}
componentWillMount() {
// Setting default tasks...
this.setState({
items: [
{
id: uuidv4(),
task: 'Default Task 1',
completed: false
},
{
id: uuidv4(),
task: 'Default Task 2',
completed: true
},
{
id: uuidv4(),
task: 'Default Task 3',
completed: false
}
]
});
}
handleOnChange = e => {
const { target: { value } } = e;
// Updating our task state with the input value...
this.setState({
task: value
});
}
handleOnSubmit = e => {
// Prevent default to avoid the actual form submit...
e.preventDefault();
// Once is submited we reset the task value and we push the
// new task to the items array.
this.setState({
task: '',
items: [
...this.state.items,
{
id: uuidv4(),
task: this.state.task,
complete: false
}
]
});
}
markAsCompleted = id => {
// Finding the task by id...
const foundTask = this.state.items.find(
task => task.id === id
);
// Updating the completed status...
foundTask.completed = true;
// Updating the state with the new updated task...
this.setState({
items: [
...this.state.items,
...foundTask
]
});
}
removeTask = id => {
// Filtering the tasks by removing the specific task id...
const filteredTasks = this.state.items.filter(
task => task.id !== id
);
// Updating items state...
this.setState({
items: filteredTasks
});
}
render() {
return (
<div className="Todo">
<h1>New Task:</h1>
<form onSubmit={this.handleOnSubmit}>
<input
value={this.state.task}
onChange={this.handleOnChange}
/>
</form>
<List
items={this.state.items}
markAsCompleted={this.markAsCompleted}
removeTask={this.removeTask}
/>
</div>
);
}
}
export default Todo;
File: src/components/Todo/index.jsx
- Now, in our List component, we need to include ReactCSSTransitionGroup and use it as a wrapper in our list elements. We need to specify the name of our transition using the transitionName prop, and transitionAppear adds a transition at the first animation mount. By default, it is false:
import React from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import './List.css';
const List = props => (
<ul>
<ReactCSSTransitionGroup
transitionName="todo"
transitionAppear={true}
>
{props.items.map((item, key) => (
<li
key={key}
className={`${item.completed ? 'completed' : 'pending'}`}
>
{item.task}
<div className="actions">
<span
className={item.completed ? 'hide' : 'done'}
onClick={() => props.markAsCompleted(item.id)}
>
<i className="fa fa-check"></i>
</span>
<span
className="trash"
onClick={() => props.removeTask(item.id)}
>
<i className="fa fa-trash"></i>
</span>
</div>
</li>
))}
</ReactCSSTransitionGroup>
</ul>
);
export default List;
File: src/components/Todo/List.jsx
- Now, using transitionName, we will add some styles using the special classes that are created by ReactCSSTransitionGroup:
.todo-enter {
opacity: 0.01;
}
.todo-enter.todo-enter-active {
opacity: 1;
transition: opacity 0.5s ease;
}
.todo-leave {
opacity: 1;
}
.todo-leave.todo-leave-active {
opacity: 0.01;
transition: opacity .5s ease-in;
}
.todo-appear {
opacity: 0.01;
transition: opacity .5s ease-in;
}
.todo-appear.todo-appear-active {
opacity: 1;
}
File: src/components/Todo/List.css