输入失去对钩子更新的关注

时间:2019-06-25 17:02:19

标签: reactjs react-hooks

我是reactjs的新手,正在尝试从输入中读取数据。问题是当我输入一个符号时,我的输入失去了焦点。但仅当所有逻辑都在函数内部时。 当带有按钮和逻辑的输入位于不同的文件中时,它将起作用。我真的不知道为什么...

我用相同的代码创建了单独的文件,并将其导入解决方案-没关系。 我尝试使用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 个答案:

答案 0 :(得分:3)

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 :(得分:1)

之所以会发生这种情况,是因为useState钩子不是“钩”到您的SearchComponent而是您的MyInput组件。每当调用updateCitySearch()时,您都会更改MyInput的状态,从而迫使 entire 组件重新呈现。

SearchComponentMyInput内部明确定义。 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>
  );
}

答案 2 :(得分:0)

我也是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>
  );
}