3

Использую реакт. Получаю с сервера массив и отображаю его как таблицу с пагинацией и сортировкой. Пагинацию и сортировку сделал в виде пользовательских хуков, они работают так как нужно. Но при первом рендере массив возвращаемый из функции сортировки куда-то девается, я так решил потому что таблица пустая, потом когда я меняю сортировку таблица заполняется в соответствии с сортировкой.

App.js:

 const [items, setItems] = useState([]);
 const {setMask, setCurrentColumn, setCurrentCondition, sortedItems} = useSort(items);
 const {setCurrentPage, currentItems, amountOfPages} = usePagination(sortedItems);
 const [isLoaded, setIsLoaded] = useState(false);

мой хук:

export const useSort = (filteredItems) => {
const [sortedItems, setSortedItems] = useState(filteredItems);
const [mask, setMask] = useState("");
const [currentColumn, setCurrentColumn] = useState("Distance");
const [currentCondition, setCurrentCondition] = useState("greater");

useEffect(() => {
    SortQuantity(currentCondition, currentColumn);
    SortDistance(currentCondition, currentColumn);
    SortName(currentCondition, currentColumn);

}, [currentCondition, currentColumn, mask]);

function SortQuantity (currentCondition, currentColumn) {
    if (currentColumn === "Quantity" && currentCondition === "less") {
        console.log(mask, currentCondition, currentColumn);
        setSortedItems(
            filteredItems.filter(item => item.Quantity < mask)
        )
    } else if (currentColumn === "Quantity" && currentCondition === "greater") {
        console.log(mask, currentCondition, currentColumn);
        setSortedItems(
            filteredItems.filter(item => item.Quantity > mask)
        )
    } else if (currentColumn === "Quantity" && currentCondition === "equal") {
        console.log(mask, currentCondition, currentColumn);
        setSortedItems(
            filteredItems.filter(item => item.Quantity.toString() === mask)
        )
    } else return sortedItems
}

function SortDistance (currentCondition, currentColumn) {
    if (currentColumn === "Distance" && currentCondition === "less") {
        console.log(mask, currentCondition, currentColumn);
        setSortedItems(
            filteredItems.filter(item => item.Distance < mask)
        )
    } else if (currentColumn === "Distance" && currentCondition === "greater") {
        console.log(mask, currentCondition, currentColumn);
        setSortedItems(
            filteredItems.filter(item => item.Distance > mask)
        )
    } else if (currentColumn === "Distance" && currentCondition === "equal") {
        console.log(mask, currentCondition, currentColumn);
        setSortedItems(
            filteredItems.filter(item => item.Distance.toString() === mask)
        )
    } else return sortedItems
}

function SortName (currentCondition, currentColumn) {
    if (currentColumn === "Name" && currentCondition === "contains") {
        console.log(mask, currentCondition, currentColumn);
        setSortedItems(
            filteredItems.filter(item =>
                item.Name.toLowerCase().includes(mask.toLowerCase())
            )
        )
    } else return sortedItems
}

return {
    setMask,
    setCurrentColumn,
    setCurrentCondition,
    sortedItems
}

};

d2207
  • 79

2 Answers2

2
  • фильтрованые строки не стейт, а мемо
  • эффект не нужен
  • функции, вызываемые из use*: или за пределы компонента, или в вызывающий use* или в useCallback
  • useFilter можно сделать короче и использовать несколько раз
const useFilter = (items, column, filterOperation, filterValue) => {
    const filteredItems = useMemo(()=>{
        const check = 
        ....
        return items.filter(check)
    },[items, column, filterOperation, filterValue])
    return filteredItems
}
  • Нельзя мапить filteredItems, компилятор говорит что это не функция. Не понимаю как использовать useCallback что в него ложить и где его вызывать. Но когда я useMemo переношу из дочернего компонента в App.js он спокойно мапиться, но не с первого раза. Поведение не изменилось, мне абсолютно не понятно почему не отрабатывает массив зависимостей? Я успешно получил массив с сервера и передаю его как часть массива зависимостей для useMemo, который в свою очередь должен перерисовать компонент, а он этого не делает тупо получает массив и ждёт пока я что-то нажму и только тогда перерисовывает. – d2207 Sep 05 '20 at 11:23
  • Даже не так, дочерний компонент с useMemo на борту получает массив, а возвращает пустой массив поэтому таблица пустая. Тоже не понятно как потому что у него изменились зависимости и он должен заново выполнить свою функцию(обработать массив) и вернуть наполненный массив – d2207 Sep 05 '20 at 11:26
  • Консоль логи это показывают, флажок isLoaded:true массив items наполнился, а filteredItems - пустой. Так сейчас, может мне не следует передавать items как начальное состояние в useState? Сделать какую-то функцию которая будет устанавливать массив items в state через setItems и потом уже эти items устанавливать как зависимость для useMemo? – d2207 Sep 05 '20 at 11:37
  • код обновите в вопросе – Sergei Kirjanov Sep 05 '20 at 16:45
0

Я решил проблему с первым рендером, теперь всё нормально. Я добавил setSortedItems в фетч - запрос. Как бы оно теперь работает нормально но я понимаю что это костыль и хотелось бы понять почему useEffect не реагировал на массив зависимостей так как я ожидал. Да я понял что надо использовать useMemo, и я использовал, но с ним такая же ситуация.

async function FetchData() {
            try {
                const response = await fetch('http://localhost:4000/items');
                const json = await response.json();
                setItems(json);
                setIsLoaded(true);
                setSortedItems(json);
                console.log(json);
            } catch (e) {
                console.log(e)
            }
        };
d2207
  • 79