Prodlem с React Hooks (стек MERN)
Внезапно после попытки добавить фильтр на страницу перестали показывать объекты (хотя они точно есть, даже новые создаются). За пару дней моих стараний ничего не получилось (даже пытался откатить код на старую версию, все равно не работает).
Домашний файл:
import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { axiosInstance } from '../helpers/axiosInstance';
import { HideLoading, ShowLoading } from '../redux/alertsSlice';
import { Col, Row, message } from 'antd';
import Bus from '../components/Bus';
function Home() {
const { user } = useSelector(state => state.users)
const [filters = {}, setFilters] = useState({});
const dispatch = useDispatch();
const [buses, setBuses] = useState([]);
const getBuses = async () => {
const tempFilters = {};
Object.keys(filters).forEach((key) => {
if (filters[key]) {
tempFilters[key] = filters[key];
}
})
try {
dispatch(ShowLoading())
const response = await axiosInstance.post(
"/api/buses/get-all-buses",
tempFilters
);
dispatch(HideLoading());
if (response.data.success) {
setBuses(response.data.data);
} else {
message.error(response.data.message);
}
} catch (error) {
dispatch(HideLoading());
message.error(error.message);
}
}
useEffect(() => {
getBuses();
//setSelectedBus();
}, [])
return (
<div>
<div className='my-3 card p-2'>
<Row gutter = {10}>
<Col lg = {6} sm = {24}>
<input type='text'
placeholder='From'
value = {filters.from}
onChange = {(e) => setFilters({ ...filters, from: e.target.value })}
/>
</Col>
<Col lg = {6} sm = {24}>
<input type='text'
placeholder='To'
value = {filters.to}
onChange = {(e) => setFilters({ ...filters, to: e.target.value })}
/>
</Col>
<Col lg = {6} sm = {24}>
<input type='date'
placeholder='Date'
value = {filters.journeyDate}
onChange = {(e) => setFilters({ ...filters, journeyDate: e.target.value })}
/>
</Col>
<Col lg = {6} sm = {24}>
<button className='primary-btn' onClick = {() => getBuses()}>
Filter
</button>
</Col>
</Row>
</div>
<div>
<Row gutter = {[15, 15]}>
{buses.filter((bus) => bus.status === "Yet to start").map((bus) => (
<Col lg = {12} xs = {24} sm = {24}>
<Bus bus = {bus} />
</Col>
))}
</Row>
</div>
</div>
)
}
export default Home
Файл busRoute (там больше всего интересует get-all-buses):
const router = require('express').Router();
const Bus = require("../models/busModel")
const authMiddleware = require("../middlewares/authMiddleware")
// add-bus
router.post('/add-bus', async (req, res) => {
try {
const existingBus = await Bus.findOne({ number: req.body.number })
if (existingBus) {
return res.status(200).send({
seccess: false,
meggage: 'Bus already exists',
})
}
const newBus = new Bus(req.body);
await newBus.save();
return res.status(200).send({
success: true,
message: 'Bus added successfully'
})
} catch (error) {
res.status(500).send({
success: false,
meggage: error.message
})
}
});
// update-bus
router.post("/update-bus", authMiddleware, async (req, res) => {
try {
await Bus.findByIdAndUpdate(req.body._id, req.body)
return res.status(200).send({
success: true,
message: 'Bus updated successfully',
})
}
catch (error) {
res.status(500).send({success: false, message: error.meggage})
}
});
// delete-bus
router.post("/delete-bus", authMiddleware, async (req, res) => {
try {
await Bus.findByIdAndDelete(req.body._id, req.body)
return res.status(200).send({
success: true,
message: 'Bus deleted successfully',
})
}
catch (error) {
res.status(500).send({success: false, message: error.meggage})
}
});
// get-all-buses
router.post("/get-all-buses", authMiddleware, async (req, res) => {
try {
const buses = await Bus.find();
return res.status(200).send({
success: true,
message: "Buses fetched successfully",
data: buses,
})
} catch (error) {
res.status(500).send({
success: false,
message: error.message
})
};
})
//get-bus-by-id
router.post("/get-bus-by-id", authMiddleware, async (req, res) => {
try {
const bus = await Bus.findById(req.body._id);
return res.status(200).send({
success: true,
message: "Buses fetched successfully",
data: bus,
})
} catch (error) {
res.status(500).send({
success: false,
message: error.message
})
};
})
module.exports = router;
p.s. Позже я понял, что данные шины просто не передаются, и консоль выдала ошибку для первого прикрепленного файла: "Строка 41:6: React Hook useEffect имеет недостающую зависимость: 'getBuses'. Либо включите ее, либо удалите зависимость массив реагирующих хуков/исчерпывающих отложений ":(
https://i.stack.imgur.com/qUxvA.png
Я использую MobgoDB:
const mongoose = require('mongoose');
const busSchema = new mongoose.Schema ({
name : {
type: String,
require: true
},
number : {
type: String,
require: true
},
capacity : {
type: Number,
require: true
},
from : {
type: String,
require: true
},
to : {
type: String,
require: true
},
journeyDate : {
type: String,
require: true
},
departure : {
type: String,
require: true
},
arrival : {
type: String,
require: true
},
type : {
type: String,
require: true
},
fare : {
type: Number,
require: true
},
seatsBooked : {
type: Array,
default:[]
},
status: {
type: String,
default: 'Yet to Start',
}
})
module.exports = mongoose.model('buses', busSchema)



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Как бы то ни было, ваш метод getBuses вызывается только один раз, когда компонент монтируется. Ваша консоль просит вас добавить свою ссылку в массив зависимостей, чтобы ее можно было повторно запускать каждый раз при обновлении getBuses. Попробуйте заменить useEffect на следующее:
useEffect(() => {
getBuses();
}, [getBuses]) // <-- This is the dependency array, filled with `getBuses`
По тем же причинам вы также можете захотеть обернуть свой метод getBuses в useCallback, что позволит лучше обрабатывать изменения его зависимостей (таких как filters, например).
РЕДАКТИРОВАТЬ 1:
Следующий фрагмент, который вы поместили в свой код
const tempFilters = {};
Object.keys(filters).forEach((key) => {
if (filters[key]) {
tempFilters[key] = filters[key];
}
})
в основном копирует каждый ключ (и связанное с ним значение) из вашего объекта filters в новый объект без применения какой-либо обработки. Поэтому вы можете избавиться от него и напрямую ссылаться на объект filters.
Еще одним улучшением было бы обернуть ваш метод getBuses в useCallback с зависимостью от filters, что гарантирует, что он всегда использует актуальные данные об этом состоянии filters при вызове вашего API.
Кроме того, вы можете обновить вызов try-catch с помощью простых методов Promises Prototype, чтобы сделать поток более читабельным (это просто предпочтение и зависит от вашего стиля кодирования).
Вот пример обновленного метода getBuses:
const getBuses = useCallback(async () => {
dispatch(ShowLoading());
axiosInstance.post("/api/buses/get-all-buses", tempFilters)
.then((response) => {
if (response?.data?.success) {
setBuses(response.data.data);
} else {
message.error(response.data.message);
}
})
.catch((error) => message.error(error.message))
.finally(() => dispatch(HideLoading()));
}, [filters]);
Еще одним улучшением будет создание динамического метода обработчика onChange для ваших входных данных. Например, вы можете сделать следующее:
const handleOnChange = useCallback(({ target: { name, value } }) => {
setFilters((prevState) => ({ ...prevState, [name]: value }));
}, []);
и добавьте атрибут name к каждому входу, таким образом вам просто нужно будет передать его handleOnChange в качестве значения реквизитам onChange. Вот пример обновленного ввода:
<input type='text'
placeholder='From'
value = {filters.from}
name = "from"
onChange = {handleOnChange}
/>
О, спасибо большое, мне помогло. Да, я хотел бы узнать больше о том, о чем вы говорите.
Я переделал функцию getBuses с помощью useCallback, но фильтры все равно не работают :(( ``` const getBuses = useCallback(async() => { const tempFilters = {}; Object.keys(filters).forEach((key ) => { if (filters[key]) { tempFilters[key] = filter[key]; } }); ..... ```
Рад, что смог быть полезен! Я отредактировал свой ответ, чтобы дать дополнительную информацию. Дайте мне знать, если вам нужна помощь в понимании этого :)
о, спасибо большое, но все равно не работает. Вот что у меня на данный момент: В get-all-buses если я напишу const buses = await Bus.find(req.body); автобусы не будут отображаться на главной странице, но если я напишу req.body._id или req .body.buses или req.body.filters то все будет работать нормально. Также я написал console.info(req.body.filters) перед этой строчной буквой, и она продолжает показывать «undefined». Я пробовал это в версии всего и вашего кода. О, я ненавижу этот проект...
О, у меня может быть идея, почему у вас возникла такая проблема. Не могли бы вы обновить свой пост, чтобы предоставить содержимое вашего файла busModel и уведомить меня, когда вы это сделаете? (Я подозреваю, что вы используете ORM с определенной структурой параметров в своих методах, которую вы не соблюдаете, что может привести к такого рода проблемам)
Я использую МонгоДБ. Я обновил пост и добавил необходимую информацию
Если вам нужно что-то еще, я могу добавить новую информацию
Извините за задержку ответа, я считаю, что ваша проблема связана с тем, как вы вызываете метод ORM мангуста. Я не знаком с этим ORM, но я предполагаю, что могут быть проблемы с форматом параметров, которые вы передаете этому методу поиска, может быть, попробовать поиграть в этом направлении?
Мы не можем видеть данные, которые находятся в состоянии, но фильтрует ли
filter((bus) => bus.status === "Yet to start")все результаты? Что конкретно не работает? Похоже, конечная точка возвращает пустой массив. Вы исследовали свой бэкенд? Пожалуйста, отредактируйте, чтобы предоставить более подробную информацию о проблеме.