← Усі задачіReact · Senior

Пошук без гонки відповідей

Напишіть хук useSearch(query, search). search(query) повертає проміс із масивом результатів. Хук повертає { results, loading }: поки запит іде, loading дорівнює true.

Відповіді можуть приходити не в тому порядку, в якому йшли запити. Показувати треба лише результат для поточного query: застаріла відповідь, що прийшла пізніше, не повинна його перезаписати. Для порожнього query - results = [] без виклику search.

Тести (4)

  1. const search = (q) => Promise.resolve([q + '1']);
    const { result } = renderHook(({ q }) => useSearch(q, search), { initialProps: { q: 'a' } });
    await waitFor(() => expect(result.current.results).toEqual(['a1']));
    expect(result.current.loading).toBe(false);
  2. const search = () => new Promise(() => {});
    const { result } = renderHook(({ q }) => useSearch(q, search), { initialProps: { q: 'a' } });
    await waitFor(() => expect(result.current.loading).toBe(true));
  3. const pending = {};
    const search = (q) => new Promise((resolve) => { pending[q] = resolve; });
    const { result, rerender } = renderHook(({ q }) => useSearch(q, search), { initialProps: { q: 'a' } });
    await waitFor(() => expect(typeof pending.a).toBe('function'));
    rerender({ q: 'ab' });
    await waitFor(() => expect(typeof pending.ab).toBe('function'));
    pending.ab(['AB']);
    await waitFor(() => expect(result.current.results).toEqual(['AB']));
    pending.a(['A']);
    await wait(30);
    expect(result.current.results).toEqual(['AB']);
  4. const search = fn(() => Promise.resolve(['x']));
    const { result } = renderHook(({ q }) => useSearch(q, search), { initialProps: { q: '' } });
    await wait(30);
    expect(search).toHaveBeenCalledTimes(0);
    expect(result.current.results).toEqual([]);
    expect(result.current.loading).toBe(false);