I'm running into a double execution of my axios request in a functional react-app, which by random inserts 1 or 2 rows instead of always just 1 row into the database. Tried to wrap it in a useEffect-Hook...did not help. By logging the execution function it seems only to run once. But on the php-side it's kind of executed twice. The strange thing is, that I've implemented the same thing in two other parts of the app (just different items) and there the same code just works fine...any help very appreciated! Thx in advance!
Js-Code in React:
function ReservationObjectsDialogAdd() {
const appState = useContext(StateContext)
const appDispatch = useContext(DispatchContext)
const [name, setName] = useState()
const handleKeyPressAddDialog = e => {
if (e.which == 13) {
setReservationObject()
}
}
// add new category
async function setReservationObject() {
try {
// set new Category
const response = await Axios.post("/Main.php?cmd=setReservationObject", { name })
console.log(response.data)
appDispatch({ type: "getReservationObjects" })
appDispatch({ type: "setOpenAddDialog", data: false })
} catch (e) {
console.log(e.message)
console.log(lang.reservationObjectAddProblem)
}
}
return (
<Dialog open={appState.openAddDialog} onClose={e => appDispatch({ type: "setOpenAddDialog", data: false })} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">{lang.addTimeName}</DialogTitle>
<DialogContent>
<TextField onChange={e => setName(e.target.value)} autoFocus margin="dense" id="name" label={lang.timeName} type="text" fullWidth required={true} onKeyPress={handleKeyPressAddDialog} />
</DialogContent>
<DialogActions>
<Button onClick={e => appDispatch({ type: "setOpenAddDialog", data: false })} color="primary">
{lang.cancel}
</Button>
<Button onClick={setReservationObject} color="primary">
{lang.add}
</Button>
</DialogActions>
</Dialog>
)
}
export default ReservationObjectsDialogAdd
PHP-Side:
case "setReservationObject":
$conn = new DBConnection($host, $dbuser, $dbpassword, $db);
$post = json_decode(file_get_contents('php://input'), true);
$maxOrder = $conn->query("SELECT MAX(orderNumber) as maxorder FROM reservationObjects", [])->fetch(PDO::FETCH_ASSOC);
$maxOrder = $maxOrder['maxorder'] + 1;
$activeCategory = $conn->query("SELECT id FROM reservationCategories WHERE active=?", [1])->fetch(PDO::FETCH_ASSOC);
$conn->query("INSERT INTO reservationObjects (category,name,orderNumber,visible) values(?,?,?,?)", [$activeCategory['id'], $post['name'], $maxOrder, 1]);
break;
Here the rendering-code:
function ReservationObjects() {
const classes = useStyles()
const appState = useContext(StateContext)
const appDispatch = useContext(DispatchContext)
const [reservationObjects, setReservationObjects] = useState([])
const [images, setImages] = useState()
//sort categories
function onSortEnd({ oldIndex, newIndex }) {
let newReservationObjects = reservationObjects.map((el, i) => {
return el
})
newReservationObjects = arrayMove(newReservationObjects, oldIndex, newIndex)
setReservationObjects(newReservationObjects)
async function sortObjects(newReservationObjects) {
try {
// sort Data in DB
const response = await Axios.post("/Main.php?cmd=sortObjects", { reservationObjects: newReservationObjects })
appDispatch({ type: "getReservationObjects" })
appDispatch({ type: "getReservationItems" })
} catch (e) {
console.log(e.message)
console.log(lang.categorySortProblem)
}
}
sortObjects(newReservationObjects)
}
// sort events- part 1
function handleDragEndSortObjects(event) {
const { active, over } = event
if (active.id !== over.id) {
const tempReservationObjects = reservationObjects.map((el, i) => {
return el
})
let oldIndex = null
let newIndex = null
tempReservationObjects.map((el, i) => {
if (active.id == el.id) {
oldIndex = i
}
if (over.id == el.id) {
newIndex = i
}
})
onSortEnd({ oldIndex, newIndex })
}
}
function handleDragEndAssignObjects(event) {
console.log(event)
}
// in Sort-Mode check if the clicked target is a interface-entity
function shouldCancelStart(e) {
console.log("enter should cancel")
if (e.target.hasAttribute("isadmin")) {
if (e.target.attributes.isadmin.value) {
console.log("enter should cancel return false")
return false
}
}
if (e.target.hasAttribute("interface")) {
if (e.target.attributes.interface.value) {
console.log("enter should cancel return true")
return true
}
}
}
// initial loading of reservation objects
useEffect(() => {
async function getReservationObjects() {
try {
const response = await Axios.post("/Main.php?cmd=getReservationObjects", { isadmin: appState.isAdmin, category: appState.activeCategoryNumber }).then(response => {
setReservationObjects(response.data)
appDispatch({ type: "getReservationTimes" })
})
} catch (e) {
console.log(lang.reservationCategoriesProblem)
}
}
getReservationObjects()
}, [appState.getReservationObjectsTrigger])
//initial loading of images
useEffect(() => {
async function loadImages() {
try {
const response = await Axios.post("/Main.php?cmd=getImages")
//console.log(response.data)
setImages(response.data)
} catch (e) {
console.log(e.message)
}
}
loadImages()
}, [])
// handle mouse leave -> background Image
function handleObjectMouseLeave(e) {
appDispatch({ type: "setBackgroundImage", data: "" })
}
//handle mouse enter -> background Image
function handleObjectMouseEnter(e) {
if (e.target.hasAttribute("image")) {
let image = e.target.attributes.image.value
appDispatch({ type: "setBackgroundImage", data: image })
}
}
const sensors = useSensors(
useSensor(PointerSensor),
useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates
})
)
function Draggable(props) {
const { attributes, listeners, setNodeRef, transform, isDragging, over } = useDraggable({
id: props.id,
category: props.category
})
const style = transform
? {
transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`
}
: undefined
return (
<div ref={setNodeRef} className="reservationArea__reservationObjectDraggable" style={style} {...listeners} {...attributes}>
<ReservationObject category={props.category} key={props.id} id={props.id} name={props.name} hover={appState.hoverObjectId == props.id ? "hovering" : ""} visible={props.visible} isadmin={appState.isAdmin.toString()} id={props.id} isactive={props.active} hovered={appState.reservationItems} image={props.image} onMouseEnter={handleObjectMouseEnter} onMouseLeave={handleObjectMouseLeave} />
</div>
)
}
function sortableVsDroppable() {
if (appState.objectsSortable) {
return (
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEndSortObjects}>
<SortableContext
items={reservationObjects.map(item => {
return item.id
})}
strategy={horizontalListSortingStrategy}
className="reservationArea__reservationObjects"
>
<div className="reservationArea__reservationObjects">
{reservationObjects.map((item, i) => (
<ReservationObject key={item.id} id={item.id} name={item.name} hover={appState.hoverObjectId == item.id ? "hovering" : ""} visible={item.visible} isadmin={appState.isAdmin.toString()} id={item.id} isactive={item.active} hovered={appState.reservationItems} image={item.image} onMouseEnter={handleObjectMouseEnter} onMouseLeave={handleObjectMouseLeave} />
))}
</div>
{appState.isAdmin ? (
<Link to="/" onClick={e => appDispatch({ type: "setOpenAddDialog", data: true })} className="reservationArea__addObject">
<AddCircleOutlineIcon />
</Link>
) : (
""
)}
</SortableContext>
</DndContext>
)
} else {
console.log("assignable")
return (
<>
<div className="reservationArea__reservationObjects">
{reservationObjects.map((item, i) => (
<Draggable key={item.id} category={item.category} id={item.id} index={item.id} name={item.name} hover={appState.hoverObjectId == item.id ? "hovering" : ""} visible={item.visible} isadmin={appState.isAdmin.toString()} id={item.id} isactive={item.active} hovered={appState.reservationItems} image={item.image} onMouseEnter={handleObjectMouseEnter} onMouseLeave={handleObjectMouseLeave} />
))}
</div>
{appState.isAdmin ? (
<Link to="/" onClick={e => appDispatch({ type: "setOpenAddDialog", data: true })} className="reservationArea__addObject">
<AddCircleOutlineIcon />
</Link>
) : (
""
)}
</>
)
}
}
return (
<div className="reservationArea__reservationObjectsContainer">
<ReservationObjectsImage />
{sortableVsDroppable()}
<ReservationObjectsDialogAdd />
<ReservationObjectsDialogEdit />
<ReservationObjectsDialogDelete />
</div>
)
}
export default ReservationObjects
Finally solved. It was in the php-part. I replaced the fetching of the activeCategory directly in mysql with a parameter that I sent with Axios. Somehow the activeCategory-fetching led to to this strange behaviour, that it randmly executed the insert-statement once or twice.