Реакция: рендеринг набора переменных в useEffect () всегда на один шаг позади - PullRequest
0 голосов
/ 09 февраля 2020

Работая над приложением для Android с использованием React Native, я наткнулся на странную проблему.

Для поиска по базе данных существует панель поиска. Результат должен быть представлен. В приведенном ниже коде вы видите, что я установил переменную с результатом в useEffect() -Крюк после определения переменной снаружи с помощью useRef(): let returnValue = useRef('No results');

Так что я ожидал, что если я наберу имя, такой как «Майк», результат базы данных (сохраненный в returnValue.current) будет отображен сразу после отправки.

Но нет.

На самом деле, результат "Mike" отображается после того, как я снова открываю панель поиска и удаляю последний символ, оставляя "Mik". Затем приложение отображает «Майк», как если бы оно было точно на шаг позади.

После поиска проблемы я только что обнаружил asyn c «проблемы» с useState() -Крючком, но не с useEffect(). Когда я делаю console.log() useState(), все настроено правильно. Даже внутри useEffect() - регистрация returnValue.current всегда дает правильный результат в правильное время. Единственная проблема - рендеринг returnValue.current с такой странной задержкой.

Кто-то может демистифицировать это поведение?

import ...

const SearchBar = props => {
  let [inputValue, setInputValue] = useState(null);
  let returnValue = useRef('No results');

  const sendInputValueToReduxStore = text => {
    setInputValue(text);
    props.setInputValueSearchBar(text);
  };

  useEffect(() => {
    // setting database schema
    const personsSchema = {
      name: 'realm',
      properties: {
        name: 'string?',
        color: 'string?',
      },
    };

    // open the database
    let database = new Realm({
      path: fs.DocumentDirectoryPath + '/default.realm',
      schema: [personsSchema ],
      readOnly: true,
    });

    // doing the database query
    const allPersons = database.objects('realm');
    let resultArray = [];
    const query = inputValue;
    const queryResult = inputValue
      ? allPersons.filtered("name == '" + query + "'")
      : 'default';
    resultArray = Array.from(queryResult);
    const personNamesArray = resultArray.map(value => value.name);
    const personNames = personNamesArray.toString();
    returnValue.current = personNames;
    // logging always correct
    console.log('person name: ', personNames);
  }, [inputValue]);

  const isText = props.text;

  return (
    <View>
      <Header searchBar rounded>
        <Item>
          <Icon name="ios-search" />
          <Input
            placeholder="Search"
            onChangeText={text => sendInputValueToReduxStore(text)}
            value={inputValue}
          />
        </Item>
      </Header>
      {isText && (
        <View>
          <Text>{props.text}</Text>
        </View>
      )}
      //returnValue.current is rendered with delay
      {returnValue && <Text>{returnValue.current}</Text>}
    </View>
  );
};

1 Ответ

1 голос
/ 09 февраля 2020

Попробуйте заменить useRef крючок на useState. Этого должно быть достаточно, поскольку returnValue - это просто вычисленное значение, полученное из inputValue:

import ...

const SearchBar = props => {
  let [inputValue, setInputValue] = useState(null);
  let [returnValue, setReturnValue] = useState(null);

  const sendInputValueToReduxStore = text => {
    setInputValue(text);
    props.setInputValueSearchBar(text);
  };

  useEffect(() => {
    // setting database schema
    const personsSchema = {
      name: 'realm',
      properties: {
        name: 'string?',
        color: 'string?',
      },
    };

    // open the database
    let database = new Realm({
      path: fs.DocumentDirectoryPath + '/default.realm',
      schema: [personsSchema ],
      readOnly: true,
    });

    // doing the database query
    const allPersons = database.objects('realm');
    let resultArray = [];
    const query = inputValue;
    const queryResult = inputValue
      ? allPersons.filtered("name == '" + query + "'")
      : 'default';
    resultArray = Array.from(queryResult);
    const personNamesArray = resultArray.map(value => value.name);
    const personNames = personNamesArray.toString();
    setReturnValue(personNames);
  }, [inputValue]);

  const isText = props.text;

  return (
    <View>
      <Header searchBar rounded>
        <Item>
          <Icon name="ios-search" />
          <Input
            placeholder="Search"
            onChangeText={text => sendInputValueToReduxStore(text)}
            value={inputValue}
          />
        </Item>
      </Header>
      {isText && (
        <View>
          <Text>{props.text}</Text>
        </View>
      )}
      {returnValue && <Text>{returnValue}</Text>}
    </View>
  );
};
...