Задать вопрос
@Bulgar

Смещение на один элемент во время поиска?

Не работает корректно поиск. К пример, ввожу 1 - ноль эмоций, на 11 он начинает искать как 1, на 111 он начинает искать на 11 и т.д.

import React, { useState, useEffect, useRef, useCallback } from 'react';
import axios from 'axios';
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';

const limit = 20;

const Table = () => {
  const [items, setItems] = useState([]);
  const [selectedIds, setSelectedIds] = useState([]);
  const [search, setSearch] = useState('');

  const offsetRef = useRef(0);
  const loadingRef = useRef(false);

  const loadItems = useCallback(async (reset = false) => {
    if (loadingRef.current) return;
    loadingRef.current = true;

    const res = await axios.get('http://localhost:5000/items', {
      params: { offset: reset ? 0 : offsetRef.current, limit, search }
    });

    if (reset) {
      setItems(res.data);
      offsetRef.current = limit;
    } else {
      setItems(prev => [...prev, ...res.data]);
      offsetRef.current += limit;
    }

    loadingRef.current = false;
  }, [search]);

  useEffect(() => { loadItems(true); }, [loadItems]);

  const handleSelect = (id) => {
    setSelectedIds(prev =>
      prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]
    );
    setItems(prev =>
      prev.map(item => item.id === id ? { ...item, selected: !item.selected } : item)
    );
  };

  const handleDragEnd = async (result) => {
    if (!result.destination) return;

    const reordered = Array.from(items);
    const [moved] = reordered.splice(result.source.index, 1);
    reordered.splice(result.destination.index, 0, moved);
    setItems(reordered);

    await axios.post('http://localhost:5000/update', {
      movedId: moved.id,
      sourceIndex: result.source.index,
      destinationIndex: result.destination.index,
      offset: offsetRef.current - items.length,
      selectedIds
    });
  };

  const handleScroll = (e) => {
    const { scrollTop, scrollHeight, clientHeight } = e.target;
    if (scrollHeight - scrollTop <= clientHeight + 5) {
      loadItems();
    }
  };

  const handleSearchChange = (e) => {
    setSearch(e.target.value);
    offsetRef.current = 0;
    setItems([]);
    loadItems(true);
  };

  return (
    <div style={{ fontFamily: 'Arial, sans-serif', padding: '20px' }}>
      <input
        placeholder="Поиск"
        value={search}
        onChange={handleSearchChange}
        style={{
          marginBottom: '15px',
          padding: '8px 12px',
          width: '250px',
          borderRadius: '8px',
          border: '1px solid #ccc',
          outline: 'none',
          transition: 'box-shadow 0.2s',
        }}
        onFocus={e => e.target.style.boxShadow = '0 0 5px #1890ff'}
        onBlur={e => e.target.style.boxShadow = 'none'}
      />
      <div
        onScroll={handleScroll}
        style={{
          height: '500px',
          overflowY: 'auto',
          border: '1px solid #ccc',
          borderRadius: '8px',
          padding: '10px',
          background: '#fafafa'
        }}
      >
        <DragDropContext onDragEnd={handleDragEnd}>
          <Droppable droppableId="list">
            {(provided) => (
              <div {...provided.droppableProps} ref={provided.innerRef}>
                {items.map((item, index) => (
                  <Draggable key={item.id} draggableId={item.id.toString()} index={index}>
                    {(provided, snapshot) => (
                      <div
                        ref={provided.innerRef}
                        {...provided.draggableProps}
                        {...provided.dragHandleProps}
                        style={{
                          display: 'flex',
                          alignItems: 'center',
                          padding: '8px 12px',
                          marginBottom: '6px',
                          borderRadius: '6px',
                          border: '1px solid #eee',
                          background: item.selected ? '#e6f7ff' : snapshot.isDragging ? '#ffe58f' : 'white',
                          boxShadow: snapshot.isDragging ? '0 4px 8px rgba(0,0,0,0.1)' : 'none',
                          transition: 'background 0.2s, box-shadow 0.2s',
                          ...provided.draggableProps.style
                        }}
                      >
                        <input
                          type="checkbox"
                          checked={item.selected || selectedIds.includes(item.id)}
                          onChange={() => handleSelect(item.id)}
                          style={{ marginRight: '12px', cursor: 'pointer' }}
                        />
                        <span style={{ fontWeight: 500 }}>{item.id}</span>
                      </div>
                    )}
                  </Draggable>
                ))}
                {provided.placeholder}
              </div>
            )}
          </Droppable>
        </DragDropContext>
      </div>
    </div>
  );
};

export default Table;
  • Вопрос задан
  • 68 просмотров
Подписаться 1 Простой 1 комментарий
Пригласить эксперта
Ответы на вопрос 1
0xD34F
@0xD34F Куратор тега React
const handleSearchChange = (e) => {
  setSearch(e.target.value);
  offsetRef.current = 0;
  setItems([]);
  loadItems(true);
};

Вызов loadItems убрать. У вас уже есть один в эффекте, и, в отличие от этого, с актуальным значением search. А этот срабатывает раньше, и, соответственно, блокирует (if (loadingRef.current) return;) запрос с правильными данными.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы