javascriptreactjsreact-hook-form

filter using react hook form not working?


I am creating a small list using React Hook Form with useFieldArray. I want to filter the list when the user types anything in the search field. However, the filtering is not working.

Below is my code:

https://playcode.io/2322411

import React from 'react';
import { useForm, useFieldArray, Controller, useWatch } from 'react-hook-form';
import ReactDOM from 'react-dom';

let renderCount = 0;

export function App() {
  const { register, control, handleSubmit, reset, watch } = useForm({
    defaultValues: {
      test: [
        { firstName: 'Bill 1', lastName: 'Luo' },
        { firstName: 'hello2', lastName: 'Luo' },
        { firstName: 'test 3', lastName: 'Luo' },
        { firstName: 'test 4', lastName: 'Luo' },
      ],
    },
  });
  const { fields, append, prepend, remove, swap, move, insert, replace } =
    useFieldArray({
      control,
      name: 'test',
    });

  const onSubmit = data => console.log('data', data);

  const [searchQuery, setSearchQuery] = React.useState('');

  const handleSearchChange = event => {
    setSearchQuery(event.target.value);
  };

  const filteredRows = fields.filter(row =>
    row.firstName.toLowerCase().includes(searchQuery.toLowerCase())
  );

  console.log(JSON.stringify(filteredRows));
  return (
    <>
      <input onChange={handleSearchChange} value={searchQuery} />

      <form onSubmit={handleSubmit(onSubmit)}>
        <ul>
          {filteredRows.map((item, index) => {
            return (
              <li key={item.id}>
                <input
                  {...register(`test.${index}.firstName`, { required: true })}
                />

                <Controller
                  render={({ field }) => <input {...field} />}
                  name={`test.${index}.lastName`}
                  control={control}
                />
              </li>
            );
          })}
        </ul>
      </form>
    </>
  );
}

// Log to console
console.log('Hello console');

when I search "test" it is showing first two rows instead of last two rows. why?


Solution

  • You are using the index of the filtered list when referring to the first name and last name. You need to refer to the index of the original list

     {filteredRows.map((item, index) => {
            return (
              <li key={item.id}>
                <input
                  {...register(`test.${fields.findIndex((i) => i === item)}.firstName`, { required: true })}
                />
    
                <Controller
                  render={({ field }) => <input {...field} />}
                  name={`test.${fields.findIndex((i) => i === item)}.lastName`}
                  control={control}
                  />
              </li>
            );
          })}