I’ve created a simple todo list to learn react and i’m trying to add some additional features. At the moment i’m trying to add buttons that toggle the list of items, so it either shows all the tasks or just those that are completed.
I’ve written a function to change the state of my visabilityFilter so I can later use this to toggle the items in the list, but it isn’t behaving how it should be.
I console log the visabilityFilter variable but it always shows the wrong state before changing to the correct state. e.g. the ‘show all’ button will console log ‘show completed’ then if you press it again it will console log ‘show all’
App.js
import React, { Component } from 'react'; import './App.css'; import TodoList from './components/TodoList.js' import VisabilityFilter from './components/VisabilityFilter.js' export const SHOW_ALL = 'show_all' export const SHOW_COMPLETED = 'show_completed' class App extends Component { constructor (props) { super(props) this.state = { inputValues: { 'newTodo': '' }, todos: [ { task: 'My First Todo', completed: false } ], visabilityFilter: SHOW_ALL } this.addTodo = this.addTodo.bind(this) this.handleInputChange = this.handleInputChange.bind(this) this.handleKeyUp = this.handleKeyUp.bind(this) this.toggleCompleted = this.toggleCompleted.bind(this) this.removeTodo = this.removeTodo.bind(this) this.checkCompleted = this.checkCompleted.bind(this) this.setVisabilityFilter = this.setVisabilityFilter.bind(this) } handleInputChange (e) { const { inputValues } = this.state const { id, value } = e.target this.setState({ inputValues: { ...inputValues, [id]: value } }) } handleKeyUp (e) { var code = e.key if(code === 'Enter') { this.addTodo(e); } } toggleCompleted (e, index) { const { todos } = this.state todos[index].completed = !todos[index].completed todos.sort((a, b) => b.completed - a.completed) this.setState({ todos }) } removeTodo (e, index) { const { todos } = this.state this.setState ({ todos: todos.filter((todo, i) => i !== index) }) } addTodo (e) { const { todos, inputValues } = this.state const { dataset } = e.target if (inputValues[dataset.for] === '') return const newTodo = { task: inputValues[dataset.for], completed: false } todos.push(newTodo) this.setState({ todos, inputValues: { ...inputValues, [dataset.for]: '' } }) } checkCompleted (e, index) { const { todos } = this.state return { todos } && todos[index].completed } setVisabilityFilter (e) { const { visabilityFilter } = this.state const { dataset } = e.target this.setState({ visabilityFilter: dataset.for }) console.log ({ visabilityFilter }) } render() { const { todos, inputValues, visabilityFilter } = this.state return ( <div className="App"> <TodoList todos={todos} inputValues={inputValues} addTodo={this.addTodo} handleInputChange={this.handleInputChange} removeTodo={this.removeTodo} toggleCompleted={this.toggleCompleted} handleKeyUp={this.handleKeyUp} checkCompleted={this.checkCompleted} /> <VisabilityFilter setVisabilityFilter={this.setVisabilityFilter} /> </div> ); } } export default App;
VisabilityFilter.js
import React from 'react' import { func } from 'prop-types' import { SHOW_ALL, SHOW_COMPLETED } from '../App' const VisabilityFilter = props => { return ( <div> <button data-for={SHOW_COMPLETED} onClick={ props.setVisabilityFilter } > Show Completed Tasks </button> <button data-for={SHOW_ALL} onClick={ props.setVisabilityFilter }> Show All Tasks </button> </div> ) } VisabilityFilter.propTypes = { setVisabilityFilter: func.isRequired } export default VisabilityFilter
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
setState()
is async (React docs), so the state changes won’t be applied immediately. If you want to log out the new state,setState()
takes in a function as the second argument and performs that function when the state is updated. So:
this.setState({ abc: xyz }, () => console.log(this.state.abc), )
Or you can also use componentDidUpdate()
, which is recommended
Method 2
In the functional components use useEffect to track for changes of state.
useEffect(() => { console.log(someState); },[someState);
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0