How to use the updated useState value? - javascript

I use DataGrid Material UI.
I want to delete the selected row by clicking on the button.
To do this, I get the ID value in the onRowSelected attribute, write it to the useState hook.
However, when I click on any row, the row I selected earlier is deleted, not the one I selected now.
I know that useState is asynchronous, but what should I do in this case?
I need to send the updated value in the delete request to the server, not the previous one.
const [selectionModel, setSelectionModel] = useState([])
const handleDeleteUser = (e) => {
const config = {
headers: {
Authorization: 'Token ' + localStorage.getItem('token')
}
}
e.preventDefault()
axios
.delete(baseUrl + '/api/v1/users/' + `${selectionModel}/` , config)
.then((res) => {
swal({
title: "Are you sure?",
buttons: [true, "Do it!"],
})
updateData()
})
<DataGrid
rows={datas}
columns={columns}
pageSize={10}
onRowSelected={(row) => {
setSelectionModel(row.data.id)
}} />
picture

From what you've shown here I can't tell you exactly what the issue is, but I would suggest setting the selected id like you currently are here in the onRowSelected event, and then (if you're wanting to delete every time you click a row), use a useEffect hook with a dependency array to call your delete logic everytime that id changes. It would look something like this:
useEffect(() => {
deleteSelection(selectionModal)
}, [selectionModal]);
const deleteSelection = (id) => {
// your delete logic here
}
If you put together a working codepen I can help you more.

Related

How to fetch data only on first click via react-query and then disable refetch on subsequent clicks

I encountered a problem while implementing the form where the data used in select, retrieved from the database via react-query, should only be retrieved once when clicking on input, and subsequent clicks should not cause a refetch.
How to do it in clean way?
Hook:
export const useUnitOfMeasureSelectData = ({
queryPageIndex,
queryPageSize,
queryFilters,
enabled,
refetchOnWindowFocus,
}) => {
return useQuery(
["unitofmeasure-list", queryPageIndex, queryPageSize, queryFilters],
() => fetchItemData(queryPageIndex, queryPageSize, queryFilters),
{
keepPreviousData: true,
staleTime: 60000,
enabled,
refetchOnWindowFocus,
select: (data) => {
const categories = data.data.results.map((obj) => ({
value: obj.id,
label: obj.name,
}));
return categories;
},
}
);
};
In component calling onClick={()=>refetch()} refetch data on every click.
const {
data: unitOfMeasureSelectData = [],
refetch: refetchUnitOfMeasureSelectData,
} = useUnitOfMeasureSelectData({
queryPageIndex: queryPageIndex,
queryPageSize: queryPageSize,
queryFilters: filterString,
enabled: false,
refetchOnWindowFocus: false,
});
looks like you want a lazy query with infinite stale time:
const [enabled, setEnabled] = useState(false)
useQuery(key, fn, { enabled, staleTime: Infinity })
then, when you click on the input, you call setEnabled: true. The infinite stale time makes sure that the query is always considered fresh, so no more background refetch is happening.
The button in react/native has a property disabled that you can set to false when you are done. Probably the way to do this is with state
<button disabled={this.state.btnDisable}/>
Then you can update the state when you first click the button
//class component
this.setState({btnDisable: false})
//function component
setbtnDisable(false)

Discord.js - How to change style of Button

This is how I create and send the button:
client.on('messageCreate', (message) => {
/* ... Checking Command ... */
const actionRow = new MessageActionRow().addComponents(
new MessageButton()
.setStyle("PRIMARY")
.setLabel("X")
.setCustomId("test"));
message.channel.send({ content: "Test", components: [actionRow] });
}
A blue Button appears in the chat, as expected.
This is my Button-Listener:
client.on("interactionCreate", (interaction) => {
if (interaction.isButton()) {
if (interaction.customId === "test") {
//Before: console.log(interaction.component);
interaction.component.setStyle("DANGER");
//After: console.log(interaction.component);
}
}
});
Logging the component-object before and after .setStyle("DANGER") also reveals, that the style got changed from Primary to Danger successfully.
But in my Discord Client, the Style/Color didn't change, and ontop of that I am getting an error, saying that the interaction failed.
The style-property doesn't seem to be read-only: https://discord.js.org/#/docs/main/stable/class/MessageButton?scrollTo=style
So what am I doing wrong?
You updated the style only locally, you didn't send the changed component back to the Discord API.
To get rid of the error "This interaction failed", you need to respond to the interaction. One way to respond is to use MessageComponentInteraction.update(), which updates the original message.
client.on("interactionCreate", (interaction) => {
if (interaction.isButton()) {
if (interaction.customId === "test") {
// Change the style of received button component
interaction.component.setStyle("DANGER");
// Respond to the interaction,
// and send updated component to the Discord API
interaction.update({
components: [
new MessageActionRow().addComponents(interaction.component)
]
});
}
}
});
To make this work with multiple buttons, use the example below.
client.on("interactionCreate", (interaction) => {
if (interaction.isButton()) {
// Make this work only for certain buttons,
// with IDs like switch_0, switch_1, etc.
if (interaction.customId.startsWith("switch_")) {
// Change the style of the button component,
// that triggered this interaction
interaction.component.setStyle("DANGER");
// Respond to the interaction,
// and send updated components to the Discord API
interaction.update({
components: interaction.message.components
});
}
}
});
For any future viewers who might be using Discordjs V14+ you can't edit the components directly anymore, so you need to recreate them in order to edit them. This is a solution I came up with that flips the color when clicked!
const collector = interaction.channel.createMessageComponentCollector({ time: 15000 });
collector.on('collect', async i => {
//loop through each action row on the embed and update it accordingly
let newActionRowEmbeds = i.message.components.map(oldActionRow => {
//create a new action row to add the new data
updatedActionRow = new ActionRowBuilder();
// Loop through old action row components (which are buttons in this case)
updatedActionRow.addComponents(oldActionRow.components.map(buttonComponent => {
//create a new button from the old button, to change it if necessary
newButton = ButtonBuilder.from(buttonComponent)
//if this was the button that was clicked, this is the one to change!
if(i.component.customId == buttonComponent.customId){
//If the button was a primary button then change to secondary, or vise versa
if(buttonComponent.style == ButtonStyle.Primary){
newButton.setStyle(ButtonStyle.Secondary)
}
else if (buttonComponent.style == ButtonStyle.Secondary){
newButton.setStyle(ButtonStyle.Primary)
}
}
return newButton
}));
return updatedActionRow
});
// and then finally update the message
await i.update({components: newActionRowEmbeds})
});

Strange behavior after React state update with new entry

In my CRUD application, I am facing a problem every time the initial state ( array list ) updates with a new entry.
Clicking on an add button should open a modal and fill out a react-hook-form. On submit should update the state by adding the new entry.
Clicking on the edit button should open a modal and load data to the react-hook-form. On submit should update the state by updating the corresponding entry.
Everything works fine until I add a new entry in the state.
The entry is displayed in the table and clicking the edit button of that or any other entry works fine. When clicking the button of any entry, again the isEdit state stops to change as it should. I have a working demo here
In App.js
These are the states in the application. One for users list, one for distinguishing between add and update functions, and the last for passing the default values to the form when updating a user.
const [users, setUsers] = useState([]);
const [isEdit, setIsEdit] = useState(false);
const [defaultValues, setDefaultValues] = useState(initialDefaultValues);
There is a list of users coming from a GET request. When the request resolves successfully, I set the returned data to the state.
// get Users
const fetchUsers = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
const resData = await res.json();
if (res.status === 200) {
setUsers(resData);
} else {
alert(resData);
}
};
// execute on component render
useEffect(() => {
fetchUsers();
}, []);
There is a component that renders a react-bootstrap-table-next and takes the data from the state.
<UsersTable
data={users}
prepareUpdateUser={prepareUpdateUser}
prepareDeleteUser={prepareDeleteUser}
/>
This table has two buttons for each entry. An edit button and a delete button. On click these buttons the two prepare functions are executed accordingly (prepareUpdateUser, prepareDeleteUser). This is the code for the prepareUpdateUser(). The function takes the user as an argument, changes the isEdit state to true, updates the defaultValues to pass to the react-hook-form, and finally opens the modal.
const prepareUpdateUser = (user) => {
setIsEdit(true);
setDefaultValues({
id: user.id,
name: user.name,
email: user.email
});
toggleUserModal();
};
When the modal close, I reset the isEdit and `defaultValues`` state to their initial values.
const [userModal, toggleUserModal] = useModali({
animated: true,
title: isEdit ? "Update User " : "Add User ",
onHide: () => {
isEdit && setIsEdit(false);
setDefaultValues(initialDefaultValues);
}
});
The problem is that after adding a new entry in the state and then try to click the edit button of any entry, everything works, but the next time you click the button the isEdit state stops updating every time the modal closes, and each time the prepareUpdateUser runs. The problem does not appear when updating an entry.
This is the code to add a new user to the users list
const addUser = (data) => {
const newArray = users.slice();
newArray.splice(0, 0, data);
setUsers(newArray);
toggleUserModal();
};
This is the code to update a user
const updateUser = (data) => {
const updatedUser = users.findIndex((user) => user.email === data.email);
const newArray = users.slice();
newArray[updatedUser] = data;
setUsers(newArray);
toggleUserModal();
};
If you are going to use the demo link, here are the steps to reproduce the problem.
Click on any edit button. Everything loads and the isEdit state is true.
Click the add button. The form is empty and the isEdit state is false.
Add a new entry.
The list updates with the new entry.
Click an edit button. Seems to work.
Click again an edit button and now isEdit is false and no data loaded in the form
Has anyone faced something similar? I am fairly new to react, and I cannot understand why this happens. Any advice will be really helpful.
Thank you all in advance.
**I have just modified below block of code**
const prepareUpdateUser = (user) => {
setIsEdit(true);
setDefaultValues({
id: user.id,
name: user.name,
email: user.email
});
};
**Newly added one useEffect**
useEffect(() => {
if (isEdit) {
toggleUserModal();
}
}, [isEdit]);
try this. Please give your valuable feedback

How to send ID with axios.delete() request

I'm making Todo List project (Pure js) and I'm trying to bind backend (node.js/express.js) with frontend. I'm stuck on the axios.delete(). All i want it to do is:When button "delete" is clicked, delete that item from the page and from the database, but I don't know how to pass the id of that item.
I am new to JavaScript.
const deleteData = () => {
axios.delete('http://localhost:3000/delete/:id', {
})
}
const deleteData = (id) => {
axios.delete('http://localhost:3000/delete/${id}', {
})
}
Did you tried this?
look for Template strings:
https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Template_literals

Axios PUT Request in React, Redux Not Working

So I want to make a PUT request to the server, but it doesn't want to work. I know that when making a PUT request you need an identifier(e.g id) for the resource and the payload to update with. So that is my problem.
In my form I have these props:
<div>
<DoorSettingsForm
onSubmit={this.submit.bind(this)}
item={this.props.location.state.item}
id={this.props.location.state.item._id}
/>
</div>
item - All the input fields, radiobuttons etc.
id - The identifier
onSubmit - the function that handles the submitting of all of the new data, here it is:
submit(values, id) {
this.props.updateSettings(values, id)
}
And inside of my really simple action I have this:
export function updateSettings(id, item) {
return dispatch => {
console.log('ID: ', id)
return axios
.put(`${settings.hostname}/locks/${id}`, item)
.then(res => console.log(res))
.catch(err => console.log(err))
}
}
One thing that I really don't understand is when I change the places of id and item on the first line the output of my console.log changes. When having id as the first parameter I get everything I've typed in my inputs (the changes) and when having item as the first parameter I'm getting this:
ID: function (action) {
if (action.payload) {
if (!(0, _isPromise2.default)(action.payload) && !(0, _isPromise2.default)(action.payload.promise)) {
return next(action);
}
Any help with my problem is really appriciated! Thanks for reading.
I forgot to call handleSubmit with my id:
form onSubmit={() => handleSubmit(id, item)}

Categories

Resources