I have a modify-button that displays a modal component according to the value of the state property "modalVisible", in other terms the modify-button trigger an event handler which update the state property but since setState is asynchronous, the modal doesn't display properly (sometimes it shows sometimes not)
Is there an alternative to show the modal immediately after clicking modify button in react ?
here is my code i have 4 Components :
The first is Todo component which is used to display the 2 other components: DisplayTasks component (to do list) and the DisplayCompletedTasks (tasks completed),
The fourth is Modal component (just an input text to change the name of the task) which is displayed when clicking on the button modify-button
First component file TaskManagements.js
import React from 'react'
import {DisplayTasks} from './DisplayTasks'
import DisplayCompletedTasks from './DisplayCompletedTasks'
export class Todo extends React.Component{
constructor(props){
super(props);
this.state={
task: '',
tasks: [],
completedTasks: [],
inputVisible: false,
completedVisible: false,
modalVisible: false,
buttonClicked: ''
};
}
toggleInputDisplay = ()=>{
this.setState(state=>({inputVisible: !state.inputVisible}));
}
handleChange = (event)=>{
// Handle input checkboxes that handle completed tasks (the alternative is to use event.target.type==="checkboxes")
if(event.target.name==="choosed"){
//document.querySelector("input[value='" + event.target.value + "']").style.background-color = ""
let arr = this.state.tasks;
arr[event.target.value].checked = !arr[event.target.value].checked;
this.setState({tasks: arr});
}
// Handle the text input storing the text within the task state property
else if(event.target.type==="text"){
this.setState({task: event.target.value});
}
}
addTask = (event)=>{
const arr = this.state.tasks;
arr.push({task: this.state.task, checked: false});
this.setState(state=>({tasks: arr, task: ''}));
}
removeTask = (event)=>{
const arr = this.state.tasks;
arr.splice(event.target.id,1);
this.setState(state=>({tasks: arr}));
}
modifyTask = (event)=>{
this.setState({modalVisible: true});
}
handleParam = (event)=>{
const name = event.target.name;
let arr = this.state.tasks;
arr.forEach(task=>(task.checked = false));
this.setState(state=>({completedVisible: !state.completedVisible, buttonClicked: name,
tasks: arr}));
console.log(this.state.tasks);
}
handleChoosedTasks = (event)=>{
//const inputVar = document.querySelectorAll("[value][name='completed']:checked");
this.setState(state=>({tasks: state.tasks.filter(task=>(!task.checked)), completedVisible: false}));
if(this.state.buttonClicked === 'complete'){
const completedTasks = this.state.tasks.filter(task=>(task.checked));
this.setState(state=>({completedTasks: state.completedTasks.concat(completedTasks)}));
console.log('completed:' + this.state.completedTasks);
}
}
render(){
console.log(this.state.tasks);
return(
<div className="h-100">
<button className="mt-4 btn btn-outline-primary" onClick={this.toggleInputDisplay}>Add Task</button>
<div className="mt-5 ">{!this.state.inputVisible ? '' : (
<div className="mb-4">
<input className="mr-1"type="text" value={this.state.task} onChange={this.handleChange}/>
<button className="btn btn-outline-secondary mr-1" onClick={this.addTask}>Add</button>
<button className="btn btn-outline-secondary" onClick={this.toggleInputDisplay}>Cancel</button>
</div>
)
}
<div className="row p-0 col-6 mx-auto ">
<span style={{"paddingLeft": "14%"}} className=" mb-0 ml-0 col-10 ">Tasks</span>
<button id="complete" name="complete" style={{"fontSize": "14px"}} className="btn btn-success col p-0" onClick={this.handleParam}>
complete</button>
<button id="remove" name="remove" style={{"fontSize": "14px","marginLeft":"5px"}} className="btn btn-danger col p-0" onClick={this.handleParam}>
remove</button>
</div>
<DisplayTasks tasks={this.state.tasks} removeTask={this.removeTask}
completedVisible={this.state.completedVisible} handleChange={this.handleChange}
handleChoosedTasks={this.handleChoosedTasks} modifyTask={this.modifyTask} modalVisible={this.state.modalVisible}/>
<span className=" mb-0 ">Completed</span>
<DisplayCompletedTasks completedTasks={this.state.completedTasks}/>
</div>
</div>
);
}
}
second file DisplayTasks.js
import React from 'react'
import ModifiedModal from './ModifiedModal.js'
import './DisplayTasks.css'
export class DisplayTasks extends React.Component{
render(){
return(
<div id="tasks" style={{"height": "40vh"}} className="mt-2 mb-5 col-6 border border-primary mx-auto ">
{!this.props.modalVisible? '' : <ModifiedModal />}
<div style={{"height": "87%"}} className=" col-12 overflow-auto">{!this.props.tasks.length ? '' : this.props.tasks.map((task,index)=>
(
<div key={`task-${index}`} className="mt-3 mr-0 d-flex p-0 w-100 border">
<div id="parent-task" style={!task.checked ? {...this.style}: {...this.style,"backgroundColor":"yellow"}} className="col-12 ml-0 p-0 d-flex">{!this.props.completedVisible ? ''
: (<label id="c-customized" className="border">
<input name="choosed" type="checkbox" value={index}
onChange={this.props.handleChange}/>
<svg width="30" height="30">
<g>
<circle className="c-b" cx="15" cy="15" r="14" stroke="magenta"/>
<polyline className="c-m" points="6,14 12,20 23,9"/>
</g>
</svg>
</label>)}
<strong className="ml-0 col-11 d-inline-block align-self-center">
{task.task}
</strong>
<button id="modify-button" className="btn btn-primary btn-circle mr-1"><i value={index} className="fas fa-pencil-alt"
onClick={this.props.modifyTask}></i></button>
</div>
</div>
)
)
}
</div>
{!this.props.completedVisible ? ''
: <button id="choosed-confirmed" className="d-flex btn btn-success" onClick={this.props.handleChoosedTasks}>
<span className="mx-auto align-self-center">Ok</span></button>}
</div>
)
}
}
The fourth is the Modal
import React from 'react'
export default function ModifiedModal(props){
console.log("modifiedModal");
return <div className="Modal d-flex ">
<label>
<button id="x-button"></button>
<span>Modify the Task</span>
<input type="text" />
</label>
</div>
}
Edit: how the react developers displays immediatly the modal just after clicking ? because it's not intuitive to click on a button and wait until the state update, i can't detect what is the pros of using react over vanilla js if it is not make things easy