Компонент функции всегда использует предыдущее состояние в рендере - PullRequest
0 голосов
/ 24 апреля 2020

Я довольно новичок в использовании хуков и функциональных компонентов.

У меня есть отфильтрованный список. Когда я пытаюсь обновить фильтр, он будет использовать последнее состояние фильтра вместо нового. Я, должно быть, пропускаю некоторые приказы рендера / изменения состояния, но я не могу понять, что это такое.

Я ценю любую помощь, которую могу получить:)

Псевдокод ниже:

export default function TransferList(props) {
  const [wholeList, setWholeList] = React.useState([]);
  const [filteredList, setFilteredList] = React.useState([]);
  const [filter, setFilter] = React.useState([]);

  return (
    <>
      <TextField
        value={filter}
        onChange={(e) => {
          // Set filter input
          setFilter(e.target.value);

          // Filter the list
          let filtered = wholeList.filter(
            (item) => item.indexOf(filter) !== -1
          );
          setFilteredList(filtered);
        }}
      />

      <List>
        {filteredList.map((item) => (
          <ListItem>Item: {item}</ListItem>
        ))}
      </List>
    </>
  );
}

Ответы [ 4 ]

1 голос
/ 24 апреля 2020

Обновления состояния являются асинхронными, и, следовательно, обновление состояния фильтра не отражается сразу после слов

Необходимо сохранить новые значения фильтра и установить состояния на основе этого

export default function TransferList(props) {

    const [wholeList, setWholeList] = React.useState([]);
    const [filteredList, setFilteredList] = React.useState([]);
    const [filter, setFilter] = React.useState([]);

    return (
        <>
            <TextField value={filter} onChange={(e) => {
                // Set filter input
                const newFilter = e.target.value;
                setFilter(newFilter)

                // Filter the list
                let filtered = wholeList.filter(item => item.indexOf(newFilter) !== -1)
                setFilteredList(filtered)
            }} />

            <List>
                {filteredList.map(item => <ListItem>Item: {item}</ListItem>)}
            </List>
        </>
    )
}
1 голос
/ 24 апреля 2020

Внутри onChange вы должны использовать сохранить значение в константе, filter не будет обновляться сразу после setFilter(filterValue), так как это асинхронная c операция.

<TextField
  value={filter}
  onChange={e => {
    const filterValue = e.target.value;
    // Set filter input
    setFilter(filterValue);

    // Filter the list
    let filtered = wholeList.filter(item => item.indexOf(filterValue) !== -1);
    setFilteredList(filtered);
  }}
/>;
0 голосов
/ 24 апреля 2020

Заказать код для увеличения читабельности

В чистом коде

Основные изменения:

  • Использование деструктурирования вместо реквизита
  • Из jsx из html возврата для повышения читабельности
  • Использование вместо indexOf
  • Добавить ключ в список

    export default function TransferList({ wholeList }) {
    
      const [filteredList, setFilteredList] = React.useState(wholeList);
      const [filter, setFilter] = React.useState([]);
    
      const handleOnChange = ({ target }) => {
        setFilter(target.value);
        const updatedFilteredList = wholeList.filter(item => item.includes(target.value));
        setFilteredList(updatedFilteredList);
      }
    
      const list = filteredList.map(item => {
        return <ListItem key={item}>Item: {item}</ListItem>
      });
    
      return (
        <>
          <TextField value={filter} onChange={handleOnChange} />
          <List>{list}</List>
        </>
      );
    }
    

и у меня есть компонент фильтра, который делает список фильтров внутри.

import React, { useState } from 'react';

function FilterInput({ list = [], filterKeys = [], placeholder = 'Search',
  onFilter }) {

  const [filterValue, setFilterValue] = useState('');

  const updateFilterValue = ev => {
    setFilterValue(ev.target.value);
    const value = ev.target.value.toLowerCase();
    if (!value) onFilter(list);
    else {
      const filteredList = list.filter(item => filterKeys.some(key => item[key].toLowerCase().includes(value)));
      onFilter(filteredList);
    }
  }

  return (
    <input className="filter-input" type="text" placeholder={placeholder}
      value={filterValue} onChange={updateFilterValue} />
  );
}

export default FilterInput;

вызов от компонента отца выглядит следующим образом

<FilterInput list={countries} filterKeys={['name']} placeholder="Search Country"
          onFilter={filterCountries} />

это в моем приложении Corona .. вы можете посмотрите на мой Github.

и посмотрите, как я строю фильтр

(https://github.com/omergal99/hello-corona)

0 голосов
/ 24 апреля 2020

Получается, что сначала мне пришлось дать начальному отфильтрованному списку весь нефильтрованный список. По какой-то причине это исправляется.

const [filteredList, setFilteredList] = React.useState(props.wholeList);

Сначала я хотел, чтобы пустой фильтр ничего не отображал, но мне, возможно, придется довольствоваться отображением всего списка, когда фильтр пуст

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...