In the following code, when I click on the buttons, the buttonsColumns state updates as expected (as evidence by the the console.log in the function moveButton), and therefore, the buttons should move instantly to the right or left depending on whether I click them with the right or left mouse button. However, the displayed position on the page only updates when I click in the input field and enter something. I don’t understand why it behaves this way. Any idea to help me?
Also, I have planned two different behaviors depending on whether I click with the right or left mouse button. I manage to capture the normal (left) click (as evidenced by the console.log), but I can’t capture the right click. Could you tell me why and how to solve this?
const AssemblyLine = props => {
let columns = {}
for (let stage of props.stages) {
columns[stage] = []
}
const [buttonsColumns, setButtonsColumns] = useState (columns)
const [newInput, setNewInput] = useState("")
const buttons = (stage) => {
const allButtons = buttonsColumns[stage].map ((input) => {
return (
<button
data-testid="assembly-item"
key = {input}
onClick = {(e) => moveButton(e, stage, input)}
>
{input}
</button>
)
})
return allButtons
}
const stages = props.stages.map ((stage, index) => {
return (
<div
data-testid="stage"
key = {index} >
<span> {stage} </span>
{buttons(stage)}
</div>
)
})
function addNewButton () {
let updatedObject = buttonsColumns
updatedObject[props.stages[0]].unshift(newInput)
setButtonsColumns (updatedObject)
setNewInput("")
}
function moveButton (e, stage, input) {
let updatedObject = buttonsColumns
updatedObject[stage]= updatedObject[stage].filter( x => x !== input)
if (e.button===0) {
console.log("clic gauche")
let positionForward = props.stages.indexOf(stage)+1
if (positionForward<props.stages.length) {
updatedObject[props.stages[positionForward]].unshift(input)
}
}
if (e.button===2) {
console.log("clic droit")
let positionBackward = props.stages.indexOf(stage)-1
if (positionBackward>0){
updatedObject[props.stages[positionBackward]].push(input)
}
}
setButtonsColumns (updatedObject)
console.log("resultat", buttonsColumns)
}
return (
<>
<input
name = "newButton"
data-testid = "add-item"
onKeyDown = {e => e.key === "Enter" ? addNewButton() : null}
onChange = {e => setNewInput(e.target.value)}
value = {newInput}
/>
<div id="stagesContainer">
{stages}
</div>
</>
);
};
export default AssemblyLine;
And here is an exemple of the props.stages passed in app.js :
"Idea",
"Development",
"Testing",
"Deployment"
]
I deleted the if condition but it didn’t work. I also tried to edit the columnsButtons structure but it didn’t help.
2
Answers
Thanks to BetterReact Developer who helped me with correcting a small mistake in the updatedObject definition and adding the onContextMenu property to the button component, here is the corrected code that works just perfectly fine :
It seems like the issue might be related to the way you are updating the state. In React, when you use the useState hook to manage state, you should avoid directly modifying the state variable. Instead, create a copy of the state and then update the copy. This ensures that React detects the state change properly.
I have updated the moveButton and addNewButton functions to use the correct approach:
And also, I’ve added the onContextMenu event for the buttons to capture the right-click and prevent the default context menu. This allows you to handle the right-click behavior in the moveButton function.
Hope this helps you out.