I created a button that change the state of a variable on click, the problem is: when i click on it, the console.log prints the variable twice, how do i avoid this problem?
My code:
function List(){
const [documents, setDocuments] = useState([])
var [isToggled, setIsToggled] = useState(true)
return (
<div className={ isToggled ? "d-flex" : "d-flex toggled"} id="wrapper">
{ console.log(isToggled)}
<div className="bg-light border-right" id="sidebar-wrapper">
<div className="sidebar-heading"> Rascunhos </div>
<div className="list-group list-group-flush">
<tr className="d-flex conteudo">
<td className="list-group-item descricao">Dashboard</td>
<td className="list-group-item qnt">1997</td>
</tr>
</div>
<div className="btn-group">
<button className="btn btn-primary btnCarregar">Carregar</button>
</div>
</div>
<button className="btn btn-primary btnToggle ml-2 mt-2" onClick={ () => setIsToggled(!isToggled) } id="menu-toggle">></button>
</div>
)
}
I had this issue as well and it had to do with StrictMode being enabled which gets added by default when you create a new React app. At first it only happened on Class Components but now will be default for functional components as well. It is by design when using useState or other Hooks.
https://github.com/facebook/react/issues/15074
Related
I create a todo list system and I use a map to make a loop for all the items I have.
But items are stuck for me in the same row in the table.
This is a system I used to build in js vanila and now for practice I run it in react.
I would be happy for a solution.
In js vanila I would use insertAdjacentHTML
But I'm looking for the solution in react
demo for the app: https://v1-todolist.netlify.app
My Problem All items in one row.
I need not all items to be on the same line I need it to be dropped line like here
Example of how the item should look properly.
This system I built it in js vanila
if i add Div it not work
It does not sit well in the table and I also get a validateDOMNesting (...) error: cannot appear as a child of .
my code App.js
import { useState } from "react";
import "./App.css";
import Form from "./Form";
import Alert from "./Alert";
function App() {
const [nameTask, setNameTask] = useState("");
const [priority, setPriority] = useState("Low");
const [list, setList] = useState([]);
const [alert, setAlert] = useState({ show: false, type: "", msg: "" });
const handlerSubmit = function (e) {
e.preventDefault();
if (!nameTask) return showAlert(true, "danger", "you cannot input empty");
const newList = {
id: new Date().getTime().toString(),
title: nameTask,
priority: priority,
};
setList([...list, newList]);
};
const showAlert = function (show = false, type, msg) {
setAlert({ show, type, msg });
};
return (
<article className="vh-100 gradient-custom-2">
{alert.show && <Alert {...alert} showAlert={showAlert} />}
<Form
list={list}
setNameTask={setNameTask}
setPriority={setPriority}
handlerSubmit={handlerSubmit}
/>
</article>
);
}
export default App;
Form.js
import React from "react";
const Form = function ({ handlerSubmit, setNameTask, setPriority, list }) {
return (
<div className="container py-5 h-100">
<div className="row d-flex justify-content-center align-items-center h-100">
<div className="col-md-12 col-xl-10">
<div className="card mask-custom">
<div className="card-body p-4 text-white">
<div className="text-center pt-3 pb-2">
<img
src="https://mdbootstrap.com/img/Photos/new-templates/bootstrap-todo-list/check1.png"
alt="Check"
width="60"
/>
<h2 className="my-4">Task List</h2>
</div>
<form className="form-task" onSubmit={(e) => handlerSubmit(e)}>
<div className="col-auto">
<input
name="name-task"
type="text"
className="form-control task-input"
id="autoSizingInput"
placeholder="Add Task"
onChange={(e) => setNameTask(e.target.value)}
/>
</div>
<select
className="form-select"
aria-label="Default select example"
onChange={(e) => setPriority(e.target.value)}
>
<option value="Low">Low</option>
<option value="Normal">Normal</option>
<option value="High">High</option>
</select>
<button type="submit" className="btn btn-primary">
submit
</button>
</form>
<table className="table text-white mb-0">
<thead>
<tr>
<th scope="col">Task</th>
<th scope="col">Priority</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
<tr className="fw-normal">
{list.map((item, index) => {
return (
<React.Fragment key={index}>
<th>
<span className="ms-2" data-name={`${item.title}`}>
{item.title}
</span>
</th>
<td className="align-middle priority-class">
<span className="badge ${value.color}">
{item.priority}
</span>
</td>
<td className="align-middle">
<h6 className="mb-0" data-id="${value.id}">
<a className="remove-link" href="#">
<span className="badge bg-gradient remove">
❌
</span>
</a>
<a className="complete-link" href="#">
<span className="badge bg-gradient complete">
✔
</span>
</a>
</h6>
</td>
</React.Fragment>
);
})}
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
);
};
export default Form;
Check this CodeSandbox
I was able to solve your issu just by adding a flex propriety to the panel that contain your list and by changing React.fragment by a div.
However it would perhaps be better to swap the node with the class fw-normal to a div and change the React.fragment to the node tr.
I was able to use the map method to display my static data in each container. There's a Modal template I created in order to provide more object/values info but if I click the button it opens all the modals of each containers at the same time because Modal tag wasn't assigned with unique index number when I mapped through my static data. Big brothers, please look at my codes and teach me how I can open only one associated Modal.
I created function Modal (template) and import to function Projects
function Modal({closeModal}) {
return (
<div className="modal-main">
<div className='modal-card'>
<img src="" />
<div className='modal-info'>
<div className='modal-title'>
<p className="title">title</p>
</div>
<div className='modal-body'>
<p className="tech">tech</p>
<p className="description">description</p>
<p className="github">github</p>
<p className="website">website</p>
</div >
<Button>detail</Button>
<Button onClick={()=> closeModal(false)}>close</Button>
</div>
</div>
</div>
)
}
export default Modal
function Projects() {
const [openModal, setOpenModal] = useState(false);
const [oneProject, setOneProject]
= useState(list_of_projects)
return (
<div className="section-header text-center mt-5">
<h4>projects</h4>
<p>list of proejcts</p>
<div className="proj-container">
{oneProject.map((item, index)=> {
return(
<div className='proj-map mx-2 my-2'key={index} >
<button type='button' className="btn btn-link " onClick={() => setOpenModal(true)}>
<div className=" proj-card card">
<img className='proj-img' src={item.thumbnail} style={{ width:300, height:300 }}/>
<div className="proj-text card-text">
<h3 className='title'>{item.title}</h3>
<h5 className='description'>description</h5>
<br/>
<h4>+</h4>
</div>
</div>
</button>
{openModal && <**Modal** closeModal={setOpenModal} /> }
</div>
)
})}
</div>
</div>
I have User.js file to submit form and I am trying to submit form using bootstrap modal. I have no problem to submit data into database.
But I have a problem to close bootstrap modal after I trigger onSubmit={createUser}.
I add onClick={handleCloseModal} and set it into false after I clicked on submit button.
But bootstrap modal isn't close. I don't have any idea what I am doing.
Here's my code in User.js.
import axios from 'axios';
import { data } from 'jquery';
import React, { useEffect, useState } from 'react';
import { Redirect, Link } from 'react-router-dom';
const Users = () => {
const [users, setUsers] = useState([]);
const [name, setName] = useState('');
const [closeModal, setCloseModal] = useState(false);
function handleCloseModal(){
document.getElementById("myModal").classList.remove("show", "d-block", "modal-open");
document.getElementsByClassName("modal-backdrop")[0].classList.remove("modal-backdrop");
}
useEffect( () => {
(
async () => {
const {data} = await axios.get('getUsers');
setUsers(data);
}
)()
}, []);
// Add
const createUser = async (e) => {
e.preventDefault();
await axios.post('createUser', {
name : name
}).then(
async () => {
const {data} = await axios.get('getUsers');
setUsers(data);
}
);
setCloseModal(true);
}
// Add
return(
<>
{/* Page Content */}
<div className="container-fluid">
<div className="row">
<div className="col-lg-12 col-md-12">
<div className="row">
<div className="col-lg-12">
<div className="card card-outline-info">
<div className="card-header">
<h4 className="m-b-0 text-white">Users</h4>
</div>
<div className="card-body">
{/* Modal */}
{!closeModal &&
<div id="myModal" className="modal bs-example-modal-lg" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true" style={{display: 'none', overflowY: 'auto'}}>
<div className="modal-dialog modal-lg">
<div className="modal-content">
<div className="modal-header">
<h4 className="modal-title" id="myModalLabel">Fields <font color="red">*</font> asterisk required</h4>
<button type="button" className="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div className="modal-body">
<form className="" id="" action="" onSubmit={createUser}>
<div className="col-md-12">
<div className="form-group row">
<label className="control-label text-right col-md-3"><font color="red">*</font> Name</label>
<div className="col-md-9">
<input type="text" id="name" className="form-control name" name='name' placeholder=""
onChange={e=>setName(e.target.value)}
/>
<small className="form-control-feedback"></small>
</div>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-info waves-effect" data-dismiss="modal">Close</button>
<button type="submit" className="btn btn-success waves-effect text-left" id="" onClick={handleCloseModal}>Create</button>
</div>
</form>
</div>
</div>
</div>
</div>
}
{/* Modal */}
{/* Content Layout Here */}
<button type="button" data-toggle="modal" data-target="#myModal" className="btn btn-xs btn-success">Add User</button>
<div className="table-responsive">
<table id="table-user">
<thead>
<tr>
<th style={{verticalAlign: 'top'}}>No</th>
<th style={{verticalAlign: 'top'}}>Name</th>
</tr>
</thead>
<tbody>
{users.map((user) => {
return(
<tr key={user.id}>
<td>{user.name}</td>
</tr>
)
})}
</tbody>
</table>
</div>
{/* Content Layout Here */}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Page Content */}
</>
);
}
export default Users;
UPDATE :
Before I submit
After I submit
Am I missing something here ?
Appreciate someone can help me on this issue.
Many thanks.
Try this:
function handleCloseModal(){
document.getElementById("myModal").classList.remove("show");
}
For Bootstrap 4 try this:
function handleCloseModal(){
document.getElementById("myModal").classList.remove("show", "d-block");
}
EDIT
To remove the grey background after the closing of modal, you can do this:
function handleCloseModal(){
document.getElementById("myModal").classList.remove("show", "d-block");
document.querySelectorAll(".modal-backdrop")
.forEach(el => el.classList.remove("modal-backdrop"));
}
You can use data-dismiss="modal" to close Modal as Close Button
If you want use state closeModal, you can do add like this:
{!closeModal && <div id="myModal">{/* ... */}</div>}
this is my code part where i have used state and also setstate functin so I can toggle state but it is in map function so it is also opening other div i just wanted to know is it possible to open only one div using toggle function
this.state = {
show: false
}
commentInputHandler = () => {
console.log("working")
this.setState({
show: !this.state.show
})
}
<div className="col-lg-8 offset-lg-2 pb-5">
{this.state.posts.map(post => (
<div key={post._id} className="card mt-4">
<div className="card-body">
<div className="d-flex justify-content-between align-items-center">
<h4 className="card-title w-75">{post.title}</h4>
<div className="w-25 text-right">
<span onClick={() => this.deletePost(post._id)} className="badge badge-danger cp">Delete</span>
<span className="badge badge-primary cp ml-3">
<Link className="text-white" to={`/postupdate/${post._id}`}>Update</Link>
</span>
</div>
</div>
<p className="card-text">
{post.body}
</p>
</div>
<div className="card-footer">
<div className="d-flex justify-content-end">
<span onClick={this.commentInputHandler} className="badge badge-pill badge-primary mr-3 cp">Comment</span>
<span onClick={this.handleClickOpen} className="badge badge-pill badge-info cp">View comment</span>
</div>
{this.state.show ?
<div>
<form className="mt-3">
<input
type="text"
className="form-control"
placeholder="Add comment"
/>
<div className="d-flex justify-content-end">
<button className="btn btn-primary btn-sm mt-2">Comment</button>
</div>
</form>
</div> : null
}
</div>
</div>
))}
</div>
Right now show state holds for only one boolean, you might change it to an object that will hold each post show condition with _id as key (of course you can add it direct into posts state, just you didn't attach it to your code...)
this.state = {
//inital as empty object
show: {}
}
componentDidMount() {
// I update state through didMount, though it is not the only truth and depends on rest code either logic
let show = {}
this.state.posts.map(post => show[post._id] = false)
this.setState({show})
}
Now you can change commentInputHandler into something dynamic
<span onClick={()=>this.commentInputHandler(post._id)} className="badge badge-pill badge-primary mr-3 cp">Comment</span>
commentInputHandler = id => {
const { show } = this.state
this.setState({
show: {...show, [id]: !show.id}
})
}
and adapt your checker
{this.state.show[post._id] ? ...
Right now, you have a single state.show that is shared by all the elements generated by map. You could make state.show an array but there is a much better way to handle this.
You should create a separate component where you will put all the code inside your map function. Put state.show and commentInputHandler inside that new child component. Then each child component will be able to show/hide itself independently of the other ones
Parent
{this.state.posts.map(post => <PostComponent key={post.id} post={post}/>)}
PostComponent
this.state = { show: false }
commentInputHandler = () => {
...
render()
return (
<div className="card mt-4">
...
I am using React 16 with Bootstrap 4.
I am using bootstrap modal to display some values. I need to reset these values whenever modal is closed.
For Modal I have created a separate component. I dont want to use React-Modal as I get all the functionality in the current modal.
I know in plain javascript it is achieved using below code:
$(".modal").on("hidden.bs.modal"){
//reset values here
};
But I dont know how this is achieved in ReactJS?
Below is my code for modal:
<div className="modal fade modal-flex" id="large-Modal-OneUser" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-lg" role="document">
<div className="modal-content">
<div className="modal-header" style={{display: 'block'}}>
<div className="row">
<div className="col-md-6">
<h2 style={{fontWeight:600}}>{newTimelineData.length > 0 ? newTimelineData[0].candidateName : ""}</h2>
</div>
<div className="col-md-6">
<span style={{display: 'inline-flex',alignItems: 'center',float:'right'}}><h4 style={{paddingRight:20}}>{isNotEmpty(this.state.scheduledFor) ? moment(this.state.scheduledFor).format("DD-MMM-YYYY"):this.checkScheduledFor(newTimelineData)}</h4>
<h3 style={{paddingRight: 10}}>{isNotEmpty(this.state.probability) ? this.getProbabilityHTML() : this.checkProbability(newTimelineData)}</h3>
{/*<button type="button" className="close" data-dismiss="modal" aria-label="Close" style={{marginTop: 0,marginBottom: 10}}>
<span aria-hidden="true">×</span>
</button>*/}
</span>
</div>
</div>
</div>
<div className="modal-body">
<div className="col-md-12">
{/*<div className="card">*/}
{/*<div className="card-block">*/}
{/* Horizontal Timeline start */}
<div className="cd-horizontal-timeline">
<div className="timeline">
<div className="events-wrapper">
<div className="events" id="foo">
<ol>
{newTimelineData.map((item, index) => (
<li key={item.id}>
<a
href="#0" onClick={()=> this.setHeaders(item)}
data-date={moment(item.scheduledFor).format('DD/MM/YYYY')}
className={index === 0 ? 'selected' : null}>
<Moment unix format="DD MMM">
{item.scheduledFor / 1000}
</Moment>
</a>
</li>
))}
</ol>
<span className="filling-line" aria-hidden="true" />
</div>
{/* .events */}
</div>
{/* .events-wrapper */}
<ul className="cd-timeline-navigation">
<li>
<a href="#0" className="prev inactive">
Prev
</a>
</li>
<li>
<a href="#0" className="next">
Next
</a>
</li>
</ul>
{/* .cd-timeline-navigation */}
</div>
{/* .timeline */}
<div className="events-content">
<ol>
{newTimelineData.map((item, index) => (
<li
key={item.id}
className={index === 0 ? 'selected' : null}
data-date={moment(item.scheduledFor).format('DD/MM/YYYY')}>
<div className="row">
<div className="col-sm-8" style={{fontSize:'1rem',paddingLeft: 3,paddingRight:0}}><b>Job</b> : {item.jobName}</div>
{isNotEmpty(joiningDate) && <div className="col-sm-4" style={{fontSize:'1rem',paddingLeft: 3,paddingRight:0}}><b>Joined Date : </b>{joiningDate}</div>}
</div>
<div className="row">
<div className="col-sm-8" style={{fontSize:'1rem',padding:0}}><b>Stage</b> : {this.props.stage}</div>
{isNotEmpty(offerDate) && <div className="col-sm-4" style={{fontSize:'1rem',paddingLeft: 0,paddingRight:0}}><b>Offer Date : </b>{offerDate}</div>}
</div>
<br></br>
<div className="row">
<div className="col-sm-12" style={{fontSize:'1rem',paddingLeft: 0}}><b>Comments</b> :<br></br>{item.comments}</div>
</div>
</li>
))}
</ol>
</div>
{/* .events-content */}
</div>
{/* Horizontal Timeline end */}
{/*</div>*/}
{/*</div>*/}
</div>
</div>
<div className="modal-footer">
<button style={{backgroundColor: '#8080808f',borderColor:'#8080808f'}}
type="button"
className="btn btn-primary waves-effect waves-light"
data-dismiss="modal">
Close
</button>
</div>
</div>
</div>
</div>
Can anyone help?
See below snapshot for the work around I have tried suggested by #Jayavel.
Implemented a small workaround and hope it's fulfills your need, With my understanding you load your modal body with state and user will change something and you store those in the same state.
While closing the modal(close button) you need to reset the initial state i.e reset to default values.
Is that right !!! check this demo
what you need is,
store your default state like below:
const initialState = {
isOpen: false,
value: "defaultvalue"
};
and in component :
class App extends Component {
constructor(props) {
super(props);
this.state = initialState; // stored defaultstate
}
toggleModal = () => {
this.setState({
isOpen: !this.state.isOpen
});
}
toggleModalClose = () => { // modal close to reset input val
this.setState(initialState);
}
handleChange = (e) => {
this.setState({
value: e.target.value //input new value
});
}
render() {
return (
<div className="App">
<button onClick={this.toggleModal}>
Open the modal
</button>
<Modal show={this.state.isOpen}
onClose={this.toggleModalClose}>
<input type="text" value={this.state.value} onChange={this.handleChange} />
</Modal>
</div>
);
}
}
Hope this helps.