Why the function I pass to another component is undefined? - reactjs

What I'm trying to do is to show a modal(which asks if you want to delete the client, yes or no) when the user deletes a client, and to do that I have passed the function as props to the modal component, when the user clicks yes, the delete function is triggered.
ClientList.js
export default function ListClients() {
const [showModal, setShowModal] = useState();
const [userlist, setUserlist] = useState([]);
function deleteClient() {
const userParams = {
clientName:
clientName,
country: country,
clientid: selectedID,
};
axios
.delete(process.env + "client", {
data: clientParams,
})
.then((response) => {
setClientlist(clientlist.filter((client) => client.id !== clientId));
})
.catch((error) => {
console.log(error);
});
}
return(
<div>
<tbody>
{userlist.length > 0 ? (
userlist.map((userlist) => (
<tr key={userlist.id}>
<td>
<div">
{userlist.id}
</div>
</td>
<td>
<button type="button" onClick= {() =>setShowModal(true) }>
Delete
</button>
</td
</tr>
</tbody>
//the idea is to pass the state for modal to show
<ModalDelete showModal={showModal} setShowModal={setShowModal} onDel={() => deleteClient(clientlist.id)}/>
</div>
);
ModalDelete.js
Modal.js
export default function ModalDelete({ showModal, setShowModal,onDel }) {
console.log(onDel)
return(
<div>
{ showModal ? <Transition.Root show={showModal}>
<div>
<p> Are you sure you want to delete the client?</p>
</div>
<div>
<button type="button" onClick={() => {onDel(); setShowModal(false);}>Yes</button>
<button type="button" onClick={() => {setShowModal(false);}} >
Go Back
</button>
</div>
</Transition.Root> : null }
</div>
);
}
So when I console log the onDel in my console it shows that is undefined. Which means nothing is passed.
Is there a way how to pass the function?

I believe there is no issue from React side but after looking to code seems broken for the delete function, as i can see you are sending a param clientlist.id while calling the onDel, hence your deleteClient function must pass all criteria required so that it should not return undefind. try to fix this code may be your issue will get resolved, one more thing while opening the delete modal you must store this clientListId to a new state so that same can be accessed from the local state, because there is no method defind to store current clicked item from user list

Related

deleting a particular id is not working when used in modal in ReactJS

I have created a ReactJS application which perform CRUD operations. And I was successfuly able to perform all the options when used by the side of the company name.
But when I created a modal for delete button so that user must confirm whether to delete or not and comeback to the list of company items page.
Here I have encountered a problem after clicking the delete button when the modal shows up and on clicking yes instead of the particular company deleted, it goes delete the recently added company from the list and the modal does not get closed.
But what I want to achieve is that when I click on delete button for particular company and after the modal gets opened I want to delete the particular company using it's id when I click confirm and get back to the complete list of companies.
Please guide me with the correction which to be made so that I can perform the delete operation correctly.
Below is my code go through it and let me know the changes needed for it.
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import { Table, Button, List } from 'semantic-ui-react';
import { useNavigate, Link } from 'react-router-dom';
import * as MdIcons from "react-icons/md"
import Modal from "#material-ui/core/Modal";
function Read() {
const [APIData, setAPIData] = useState([]);
useEffect(() => {
axios.get(`https://62a6f21797b6156bff833b05.mockapi.io/CRUD`)
.then((response) => {
console.log(response.data)
setAPIData(response.data);
})
}, []);
const setData = (data) => {
let { companyName } = data;
localStorage.setItem('Company Name', companyName);
}
const getData = () => {
axios.get(`https://62a6f21797b6156bff833b05.mockapi.io/CRUD`)
.then((getData) => {
setAPIData(getData.data);
})
}
const onDelete = (id) => {
axios.delete(`https://62a6f21797b6156bff833b05.mockapi.io/CRUD/${id}`)
.then(() => {
getData();
})
}
let navigate = useNavigate();
const addUser = () => {
navigate("/company/create");
}
const [open, setOpen] = useState(false);
const modalOpen = () => setOpen(!open);
return (
<div className='container-fluid'>
<Button primary onClick={addUser}>Add Company</Button>
<Table singleLine>
<Table.Header>
<Table.Row>
<Table.HeaderCell>List of Companies</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{APIData.map((data) => {
return (
<Table.Row>
<Table.Cell>
<List>
<List.Item>
<Link to="/company/view">
<button style={{background:"transparent",border:"none",color:"blue"}} onClick={() => setData(data)}>{data.companyName}</button>
</Link>
</List.Item>
</List>
</Table.Cell>
<Table.Cell>
<Button color='red' onClick={() => onDelete(data.id)}>
<MdIcons.MdDelete color='white' fontSize="1.3rem" />
</Button>
<Button color="green" onClick={modalOpen}>
<MdIcons.MdDelete color='white' fontSize="1.3rem" />
</Button>
<Modal
onClose={()=>setOpen(!open)}
open={open}
style={{position: 'absolute',border: '2px solid #000',backgroundColor: 'gray',boxShadow: '2px solid black',height:150,width: 300,margin: 'auto'}}>
<>
<h2 className="text-lg-center">Are You Sure?</h2>
<div className="row">
<div className="col-lg-6">
<Button color='red' onClick={() => onDelete(data.id)}>Yes</Button>
</div>
<div className="col-lg-6">
<Link to='/company/list'>
<Button primary onClick={() => modalOpen(!open)}>Cancel</Button>
</Link>
</div>
</div>
</>
</Modal>
</Table.Cell>
</Table.Row>
)
})}
</Table.Body>
</Table>
</div>
)
}
export default Read;

Why onClick can't trigger the delete function?

What I'm trying to do is when the user clicks the delete button to delete the client, I want to show a modal that asks: Are you sure you want to delete it, yes or no.
The modal is on another component, and I thought to pass the delete function as props, but when I call the function in onClick method in the yes button, it won't delete.
ClientList.js
export default function ListClients() {
const [showModal, setShowModal] = useState();
const [userlist, setUserlist] = useState([]);
function deleteClient() {
const userParams = {
clientName:
clientName,
country: country,
clientid: selectedID,
};
axios
.delete(process.env + "client", {
data: clientParams,
})
.then((response) => {
setClientlist(clientlist.filter((client) => client.id !== clientId));
})
.catch((error) => {
console.log(error);
});
}
return(
<div>
<tbody>
{userlist.length > 0 ? (
userlist.map((userlist) => (
<tr key={userlist.id}>
<td>
<div">
{userlist.id}
</div>
</td>
<td>
<button type="button" onClick= () => setShowModal(true)}>
Delete
</button>
</td
</tr>
</tbody>
<ModalDelete showModal={showModal} setShowModal={setShowModal} onDel={() => deleteClient(clientlist.id)}/>
</div>
);
ModalDelete.js
export default function ModalDelete({ showModal, setShowModal, onDel}) {
return(
<div>
{ showModal ? <Transition.Root show={showModal}>
<div>
<p> Are you sure you want to delete the client?</p>
</div>
<div>
<button type="button" onClick={() => onDel()}>Yes</button>
<button type="button" onClick={() => {setShowModal(false);}} >
Go Back
</button>
</div>
</Transition.Root> : null }
</div>
);
}
Not sure why the client is not deleted
ModalDelete.js
onClick={() => onDel()}
shoud be
onClick={onDel}

How can I return back to the page after I click yes in a modal?

I have just implemented the modal, when the user deletes a client, the client is deleted.
But the problem is that when I click yes in modal to delete the client, the modal is still open and it won't close.
ClientList.js
export default function ListClients() {
const [showModal, setShowModal] = useState();
const [userlist, setUserlist] = useState([]);
function deleteClient() {
const userParams = {
clientName:
clientName,
country: country,
clientid: selectedID,
};
axios
.delete(process.env + "client", {
data: clientParams,
})
.then((response) => {
setClientlist(clientlist.filter((client) => client.id !== clientId));
})
.catch((error) => {
console.log(error);
});
// const openModal = () => {
// setShowModal(prev => !prev);
// };
}
return(
<div>
<tbody>
{userlist.length > 0 ? (
userlist.map((userlist) => (
<tr key={userlist.id}>
<td>
<div">
{userlist.id}
</div>
</td>
<td>
<button type="button" onClick={() => {setSelectedID(clientlist.id); setShowModal(true)}}>
Delete
</button>
</td
</tr>
</tbody>
//the idea is to pass the state for modal to show
<ModalDelete showModal={showModal} setShowModal={setShowModal} onDel={deleteClient(clientlist.id)}/>
</div>
);
ModalDelete.js
export default function ModalDelete({ showModal, setShowModal,onDel }) {
return(
<div>
{ showModal ? <Transition.Root show={showModal}>
<div>
<p> Are you sure you want to delete the client?</p>
</div>
<div>
<button type="button" onClick={onDel}>Yes</button>
<button type="button" onClick={() => {setShowModal(false);}} >
Go Back
</button>
</div>
</Transition.Root> : null }
</div>
);
}
How can I not show the modal after the user clicks yes to delete the client?
Calling setShowModal(false) after onDel:
<button type="button" onClick={() => {
onDel();
setShowModal(false);
}}>Yes</button>
And rewrite ModalDelete in this way:
<ModalDelete showModal={showModal} setShowModal={setShowModal} onDel={() => deleteClient(clientlist.id)}/>

How i can empty my state after rendering the result?

i make a to do list and i have 2 problems.
The first one : When i write something on my input and i click on my button (addTask) i need to click 2 times to have the result on my console.log . How i can do to have the result directly whn i click the first time ?
The second one : Nothing is rendered on my .map but all my values are on my array todoList . Did i do something wrong ?
function Task() {
const [task, setTask] = useState("");
const [encours, setEncours] = useState("en cours");
const [todoList, setTodoList] = useState([]);
const switchEnCours = () => {
setEncours("terminé");
};
const deleteTask = () => {
setEncours("supprimée");
};
const handleInput = (e) => {
e.preventDefault();
setTask(e.target.value);
};
const AddTask = (e) => {
setTodoList([...todoList, task]);
console.log(todoList);
};
return (
<div>
<input onChange={handleInput}></input>
<button onClick={AddTask}>Valider</button>
<div className="DivColonne">
<div className="Colonne">
<h1>Tâche à faire</h1>
{todoList !== "" ? (
todoList.map((insertTask) => {
<div>
<p>{insertTask}</p>
<button onClick={switchEnCours}>{encours}</button>
</div>;
})
) : (
<div></div>
)}
</div>
<div className="Colonne">
<h1>Tâche en cours</h1>
{encours === "terminé" ? (
<div>
{todoList.map((insert) => {
return (
<div>
<p>{insert}</p>
<button onClick={deleteTask}>{encours}</button>
</div>
);
})}
</div>
) : (
<div></div>
)}
</div>
<div>
<h1>Tâches terminées</h1>
{encours === "supprimée" ? (
<div>
<p>{todoList}</p>
</div>
) : (
<div></div>
)}
</div>
</div>
</div>
);
}
export default Task;
React state updates are asynchronously processed. This means you cannot console log the state right after an update has been enqueued and expect to see the updated value. Use a useEffect hook with dependency on the state you are updating to log state updates.
useEffect(() => console.log(todoList), [todoList]);
You are also not returning JSX when you are mapping the todos.
{todoList.map((insertTask) => {
<div>
<p>{insertTask}</p>
<button onClick={switchEnCours}>{encours}</button>
</div>;
})}
Should be
{todoList.map((insertTask) => {
return (
<div>
<p>{insertTask}</p>
<button onClick={switchEnCours}>{encours}</button>
</div>
);
})}
or directly returned
{todoList.map((insertTask) => (
<div>
<p>{insertTask}</p>
<button onClick={switchEnCours}>{encours}</button>
</div>
))}
Don't forget that when mapping lists and arrays in React to use a React key. If your tasks don't have a unique property then I highly suggest adding a GUID to each todo when it's created.
Example:
{todoList.map((insertTask) => (
<div key={task.id}>
<p>{insertTask}</p>
<button onClick={switchEnCours}>{encours}</button>
</div>
))}
your 1st problem is that you show data in "console.log()" and the nature of console.log that it shows the previous value/data(state), it's better that you used "alert()" instead.
todoList is array you need iterate here check https://reactjs.org/docs/lists-and-keys.html
<div>
<h1>Tâches terminées</h1>
{encours === "supprimée" ? (
<div>
{todoList.map(value => <p>{value}</p>}
</div>
) : (
<div></div>
)}
</div>
About console.log, you printing results after you change state, state updating is async, so it won't happen instantly.
Can change to
const AddTask = (e) => {
const newList = [...todoList, task]
console.log(newList);
setTodoList(newList);
};
About second part, this condition is redundant {todoList !== "" ? ( todoList is an Array, if it's empty .map never get executed.
Can you comment out this and check {encours === "terminé" ? ( ?
Also can't print Array in jsx
<div>
// <p>{todoList}</p>
<p>{JSON.stringify(todoList, null, 2)</p> --< try this
</div>
There are bunch of wrong things you have done in your code.
1- Since the process of setting a state is Asynchronous, logging the todoList state right after the setTodoList won't give you the latest version of it.
To log the latest version of your state, you have to register an effect:
React.useEffect(() => console.log(todoList), [todoList])
2- It's better to use setTodoList(todoList => [...todoList, task]).
3- Since todoList is an array, checking todoList !== "" is redundant and it will always pass.
4- You missed to return the DOM Node here:
todoList.map((insertTask) => {
<div>
<p>{insertTask}</p>
<button onClick={switchEnCours}>{encours}</button>
</div>;
})
5- Also you missed to use a decent key prop on loops:
todoList.map((insertTask) => {
<div key={insertTask.toString()}>
<p>{insertTask}</p>
<button onClick={switchEnCours}>{encours}</button>
</div>;
})
Check out this article for more information on this matter.
And for your main question "How to empty your state" you have to use a controlled text input instead of uncontrolled one:
<input onChange={handleInput} value={task} />
Then to empty your state, all you have to do is:
const AddTask = (e) => {
setTodoList(state => [...state, task]);
setTask("");
};

How to pass parameter to a function on onClick event in ReactJS

class UserList extends Component{
constructor() {
super();
this.state = {
list: [],
};
}
componentDidMount() {
this.getList();
}
getList(){
axios
.get('/getList')
.then(response => {
if(response.data.status == 'success'){
this.setState({
list: response.data.list,
});
console.log(response);
}
})
.catch(error => {
if (error.response) {
console.log(error.response);
}
});
}
{/*I want to call this function with userid when remove button is pressed */}
deleteUser(){
}
render(){
if(!localStorage.getItem('name')){
return( <Redirect to={'/login'} /> )
}
return (
<div id="wrapper">
<table className="table table-hover">
<thead>
<tr>
<th>#No</th>
<th>#Name</th>
<th>#Delete</th>
</tr>
</thead>
<tbody>
{
this.state.list.map(function(item, i){
return <React.Fragment>
<tr key={i}>
<td>{item.id}</td>{/* **This is user id** */}
<td>{item.name}</td>
<td>
<button type="button" onClick="deleteUser(item.id)" className="btn btn-danger btn-sm">Remove</button>
</td>
</tr>
</React.Fragment>
})
}
</tbody>
</table>
</div>
)
}
}
export default UserList;
I am new to ReactJS. I am trying to pass userid to function with onClick event to Remove button. But unable to send userid and it shows error. How can I do it. Can anybody help me with this.
I am trying to pass userid to function with onClick event to Remove button. But unable to send userid and it shows error. How can I do it. Can anybody help me with this.
I am trying to pass userid to function with onClick event to Remove button. But unable to send userid and it shows error. How can I do it. Can anybody help me with this.
Your handler is not bound. You need to declare it like this:
onClick={() => this.deleteUser(item.id)}
So change it to:
{this.state.list.map((item, i) => {
return <React.Fragment>
<tr key={i}>
<td>{item.id}</td>{/* **This is user id** */}
<td>{item.name}</td>
<td>
<button
type="button"
onClick={() => this.deleteUser("asd")}
className="btn btn-danger btn-sm"
>
Remove
</button>
</td>
</tr>
</React.Fragment>
})}
And your handler:
deleteUser = (id) => {
console.log(id)
}
You can call a function in ReactJS with:
<button type="button" onClick={() => deleteUser(item.id)}>...</button>
The function call is an expression and hence you need to use {} instead of double quotes.
Another essential ingredient for this to work is the context in which it is called. Currently it is inside a function, like so:
.map(function(item, i) {
})
The function here owns the usage of this inside it and hence this.deleteUser will not work. To get this to work, you need to convert function to an arrow function which has no this binding.
.map((item, i) => {
return (
<button type="button" onClick={() => deleteUser(item.id)}>...</button>
)
})

Resources