Reputation: 29
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
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