Devious Cuttlefish
Devious Cuttlefish

Reputation: 29

React To Do List Filter

I've been struggling with this issue and although I've gotten great advice, I haven't been able to turn it into a workable solution for my application. So, I figured I needed to add additional context to see if someone can get me to that "aHA!" moment.

I have a working filter for my to do list. However, since I can't seem to get it to work without using functions that alter the state, I wanted to provide more code. Basically, I'm using a component called Filter that renders the actual buttons for displaying the filtered lists (All, Active, Completed). This filter then passes the onClick event to the App.tsx as props. This is the code for my App.tsx where everything works... except the part where I keep my original data after choosing a filter option.

import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Header from './components/layout/Header';
import Todos from './components/Todos';
import AddTodo from './components/AddTodo.js';
import Contact from './components/pages/Contact';
import uuid from 'uuid';
import axios from 'axios';

import './App.css';
import Filter from './components/Filter';

class App extends Component {
  state = {
    todos: []
  };

  filAll = () => {
    this.setState({
      todos: this.state.todos
    });
  }

  filActive = () => {
    this.setState({
      todos: this.state.todos.filter(todo => !todo.completed)
    });
  }

  filComplete = () => {
    this.setState({
      todos: this.state.todos.filter(todo => todo.completed)
    });
  }
  componentDidMount() {
    axios
      .get('https://jsonplaceholder.typicode.com/todos?_limit=3')
      .then(res => this.setState({ todos: res.data }));
  }

  markComplete = id => {
    this.setState({
      todos: this.state.todos.map(todo => {
        if (todo.id === id) {
          todo.completed = !todo.completed;
        }
        return todo;
      })
    });
  };

  delTodo = id => {
    axios.delete(`https://jsonplaceholder.typicode.com/todos/${id}`).then(res =>
      this.setState({
        todos: [...this.state.todos.filter(todo => todo.id !== id)]
      })
    );
  };

  addTodo = title => {
    axios
      .post('https://jsonplaceholder.typicode.com/todos', {
        title,
        completed: false
      })
      .then(res => {
        res.data.id = uuid.v4();
        this.setState({ todos: [...this.state.todos, res.data] });
      });
  };

  render() {
    return (
      <Router>
        <div className="App">
          <div className="container">
            <Header />
            <Route
              exact
              path="/"
              render={props => (
                <React.Fragment>
                  <AddTodo addTodo={this.addTodo} />
                  <Filter 
                  filAll={this.filAll}
                  filActive={this.filActive}
                  filComplete={this.filComplete}
                  />
                  <Todos
                    todos={this.state.todos}
                    markComplete={this.markComplete}
                    delTodo={this.delTodo}
                  />
                </React.Fragment>
              )}
            />
            <Route path="/contact" component={Contact} />
          </div>
        </div>
      </Router>
    );
  }
}

export default App;

Upvotes: 0

Views: 688

Answers (1)

Zohaib Ijaz
Zohaib Ijaz

Reputation: 22885

You need two states. allTodos and todos

import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Header from './components/layout/Header';
import Todos from './components/Todos';
import AddTodo from './components/AddTodo.js';
import Contact from './components/pages/Contact';
import uuid from 'uuid';
import axios from 'axios';

import './App.css';
import Filter from './components/Filter';

class App extends Component {
  state = {
    allTodos: [],
    todos: []
  };

  filAll = () => {
    this.setState({
      todos: [...this.state.allTodos]
    });
  }

  filActive = () => {
    this.setState({
      todos: this.state.allTodos.filter(todo => !todo.completed)
    });
  }

  filComplete = () => {
    this.setState({
      todos: this.state.allTodos.filter(todo => todo.completed)
    });
  }
  componentDidMount() {
    axios
      .get('https://jsonplaceholder.typicode.com/todos?_limit=3')
      .then(res => this.setState({ allTodos: res.data, todos: res.data }));
  }

  markComplete = id => {
    this.setState({
      allTodos: [...this.state.allTodos.map(todo => {
        if (todo.id === id) {
          todo.completed = !todo.completed;
        }
        return todo;
      })]
    });
  };

  delTodo = id => {
    axios.delete(`https://jsonplaceholder.typicode.com/todos/${id}`).then(res =>
      this.setState({
        todos: [...this.state.allTodos.filter(todo => todo.id !== id)]
      })
    );
  };

  addTodo = title => {
    axios
      .post('https://jsonplaceholder.typicode.com/todos', {
        title,
        completed: false
      })
      .then(res => {
        res.data.id = uuid.v4();
        const todos =  [...this.state.allTodos, res.data];
        this.setState({ todos, allTodos: todos  });
      });
  };

  render() {
    const { todos } = this.state;
    return (
      <Router>
        <div className="App">
          <div className="container">
            <Header />
            <Route
              exact
              path="/"
              render={props => (
                <React.Fragment>
                  <AddTodo addTodo={this.addTodo} />
                  <Filter 
                  filAll={this.filAll}
                  filActive={this.filActive}
                  filComplete={this.filComplete}
                  />
                  <Todos
                    todos={todos}
                    markComplete={this.markComplete}
                    delTodo={this.delTodo}
                  />
                </React.Fragment>
              )}
            />
            <Route path="/contact" component={Contact} />
          </div>
        </div>
      </Router>
    );
  }
}

export default App;

Upvotes: 1

Related Questions