Ввод теряет фокус при обновлении хуков - PullRequest
2 голосов
/ 25 июня 2019

Я новичок в Reactionjs и пытаюсь прочитать данные с ввода. Проблема в том, что когда я набираю знак, мой ввод теряет фокус. Но только когда вся логика находится внутри функции. Когда ввод с кнопкой и логикой находится в другом файле - это работает. Я действительно не знаю почему ...

Я создал отдельный файл с тем же кодом и импортировал его в решение - это нормально. Я пытался с onChange = {handleChange} - также потерял фокус.

export default function MyInput(){
const [citySearch, updateCitySearch] = useState();

function searchCityClick(){
   alert(citySearch);
}
const SearchComponent = ()=> (
    <div> 
        <input 
        value={citySearch}
        onChange={(e) => updateCitySearch(e.target.value)}/>
        <Button variant="contained" color="primary" onClick={searchCityClick}>
            Search
        </Button>
    </div>

);
return(
    <div>
        <div>
            <SearchComponent />
        </div>
    </div>
)}

Ответы [ 3 ]

3 голосов
/ 25 июня 2019

SearchComponent является функциональным компонентом и не должен определяться внутри другого компонента. Определение SearchComponent внутри MyInput приведет к воссозданию SearchComponent (без перерисовки), и, по сути, его DOM будет удален, а затем добавлен обратно при каждом нажатии.

Решение довольно простое, извлеките SearchComponent из MyInput и передайте функции и данные через объект props:

const { useState, useCallback } = React;

const SearchComponent = ({ citySearch, updateCitySearch, searchCityClick }) => (
  <div> 
    <input
      value={citySearch}
      onChange={e => updateCitySearch(e.target.value)} />
    
    <button onClick={searchCityClick}>Search</button>
  </div>
);

const MyInput = () => {
  const [citySearch, updateCitySearch] = useState('');

  const searchCityClick = () => alert(citySearch);

  return(
    <div>
      <SearchComponent 
        citySearch={citySearch} 
        updateCitySearch={updateCitySearch}
        searchCityClick={searchCityClick} />
    </div>
  );
};

ReactDOM.render(
  <MyInput />,
  root
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>
1 голос
/ 25 июня 2019

Это происходит потому, что хук useState не "привязан" к вашему SearchComponent, а к вашему MyInput компоненту.Всякий раз, когда вы вызываете updateCitySearch(), вы изменяете состояние MyInput, таким образом вынуждая компонент whole выполнить повторную визуализацию.

SearchComponent, явно определено внутри MyInput.Когда citySearch-state обновляется, SearchComponent теряет фокус, потому что начальный virual DOM, окружающий его, больше не является целым, вместо этого у вас есть совершенно новый кусок DOM.По сути, вы создаете совершенно новый SearchComponent каждый раз, когда MyInput обновляется по состоянию.

Рассмотрите следующий пример:

function App() {
  const [citySearch, updateCitySearch] = useState("");
  console.log("rendered App again"); //always prints
  const SearchComponent = () => {
    console.log("rendered Search"); //always prints
    const searchCityClick = () => {
      alert(citySearch);
    };
    return (
      <div>
        <input
          value={citySearch}
          onChange={e => {
            updateCitySearch(e.target.value);
          }}
        />
        <button onClick={searchCityClick}>Search</button>
      </div>
    );
  };
  return (
    <div>
      <div>
        <SearchComponent />
      </div>
    </div>
  );
}

Каждый раз, когда вы обновляете состояние, вы должныактивировать console.log(), компонент приложения перерисовывается, а SearchComponent создается заново.Новая итерация myInput отображается каждый раз, и создается новый SearchComponent.

Но если бы вы определили useState внутри SearchComponent, то только SearchComponent будет повторно визуализироваться, когдасостояние изменяется, в результате чего исходный компонент myInput остается неизменным, а текущий SearchComponent не изменяется.

function App() {
  console.log("rendered App again"); //would never print a 2nd time.
  const SearchComponent = () => {
    const [citySearch, updateCitySearch] = useState("");
    console.log("rendered Search"); //would print with new state change
    const searchCityClick = () => {
      alert(citySearch);
    };
    return (
      <div>
        <input
          value={citySearch}
          onChange={e => {
            updateCitySearch(e.target.value);
          }}
        />
        <button onClick={searchCityClick}>Search</button>
      </div>
    );
  };
  return (
    <div>
      <div>
        <SearchComponent />
      </div>
    </div>
  );
}
0 голосов
/ 25 июня 2019

Я также новичок в React, так что возьмите мое объяснение с щепоткой соли (надеюсь, кто-то еще может уточнить). Я считаю, что это как-то связано с компонентами вложения и с тем, как React выполняет рендеринг ..

Если вы используете SearchComponent в качестве переменной вместо анонимной функции, это будет работать как положено.

Мне также любопытно, почему использование таких вложенных функций (при использовании JSX) вызывает такое поведение ... возможно, анти-паттерн?

function MyInput() {
  const [citySearch, updateCitySearch] = React.useState();

  function searchCityClick() {
    alert(citySearch);
  }
  
  const SearchComponent = (
      <div> 
          <input 
          value={citySearch}
          onChange={(e) => updateCitySearch(e.target.value)}/>
          <button variant="contained" color="primary" onClick={searchCityClick}>
              Search
          </button>
      </div>
  );
  
  return (
    <div>
      <div>
        {SearchComponent}
      </div>
    </div>
  );
}


let div = document.createElement("div");
div.setAttribute("id", "app");
document.body.append(div);
ReactDOM.render(<MyInput />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>

Даже если вы измените вложенную функцию на «фактический компонент», фокус теряется после каждого нажатия клавиши (или onChange) ..

Не работает:

function MyInput() {
  const [citySearch, updateCitySearch] = React.useState();

  function searchCityClick() {
    alert(citySearch);
  }

  const SearchComponent = () => {
      return (
        <div> 
            <input 
            value={citySearch}
            onChange={(e) => updateCitySearch(e.target.value)}/>
            <button variant="contained" color="primary" onClick={searchCityClick}>
                Search
            </button>
        </div>
    );
  }

  return (
    <div>
      <div>
        <SearchComponent />
      </div>
    </div>
  );
}
...