#mysql #reactjs #double #rows
Вопрос:
Я сталкиваюсь с двойным выполнением моего запроса axios в функциональном приложении react, которое случайным образом вставляет 1 или 2 строки вместо всегда только 1 строки в базу данных. Попытался завернуть его в полезный крючок…не помогло. Регистрируя функцию выполнения, кажется, что она запускается только один раз. Но на стороне php это вроде как выполняется дважды. Странно то, что я реализовал то же самое в двух других частях приложения (просто разные элементы), и там тот же код просто отлично работает…любая помощь очень ценится! Thx заранее!
Js-Код в 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-Сторона:
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;
Вот рендеринг-код:
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
Комментарии:
1. Здесь вы можете увидеть, что происходит в приложении: recordit.co/M18FnajjUk
2. По этому gif нельзя определить, вызываете ли вы
setReservationObject
дважды или только один раз, или сколько запросов сделано. Вы подтвердили, что делаете только один запрос API? Похоже, это проблема с тем, где вы раздираете пользовательский интерфейс. Можете ли вы обновить свой вопрос, чтобы включить код рендеринга?3. Просто добавил код рендеринга. Если я регистрирую выполнение
setReservationObject()
, оно регистрируется только один раз.4. Как вы можете видеть здесь,
setReservationObject()
это выполняется только один раз. И если вы наблюдаете за добавлением объектов, как только он добавляет два элемента, как только он добавляет только один (что было бы правильно). recordit.co/mzJA3ygaEr5. Итак, если я правильно прочитал, вы сопоставляете реквизит для
SortableContext
? Попробуйте сократить свой код до гораздо более простого компонента, без сортировки/перетаскивания/перемещения/и т.д. Элементов массива, чтобы увидеть, где он нарушается. Мне этоarrayMove
кажется подозрительным.
Ответ №1:
Наконец-то решено. Это было в php-части. Я заменил выборку категории activeCategory непосредственно в mysql параметром, который я отправил с Axios. Каким-то образом выборка activeCategory привела к такому странному поведению, что она случайно выполнила инструкцию insert один или два раза.