【问题标题】:Input is loosing focus on hooks update输入正在失去对钩子更新的关注
【发布时间】:2019-06-25 17:02:19
【问题描述】:

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

我已经创建了具有相同代码的单独文件并将其导入到 sollution - 没关系。 我已经尝试过 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>
)}

【问题讨论】:

  • 每当状态发生变化时,react 都会尝试重新渲染组件并再次创建 SearchComponent 函数,这与以前不同并导致焦点丢失。

标签: reactjs react-hooks


【解决方案1】:

SearchComponent 是一个功能组件,不应在另一个组件中定义。在MyInput 中定义SearchComponent 将导致SearchComponent 被重新创建(而不是重新渲染),本质上它的DOM 将被删除,然后在每次点击时重新添加。

解决方案非常简单,从MyInput 中提取SearchComponent,然后通过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>

【讨论】:

  • 就是这样!我以为渲染元素有问题,但不知道如何处理。非常感谢您的帮助!
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    发生这种情况是因为 useState 钩子没有“挂钩”到您的 SearchComponent,而是您的 MyInput 组件。无论何时,您调用updateCitySearch() 都会更改MyInput 的状态,从而强制整个 组件重新渲染。

    SearchComponent,在MyInput 中明确定义。当 citySearch-state 更新时,SearchComponent 失去焦点,因为围绕它的初始 virual DOM 不再完整,而是您拥有一个全新的 DOM。从本质上讲,每次 MyInput 按状态更新时,您都会创建一个全新的 SearchComponent

    考虑以下示例:

    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(),App 组件会重新渲染,SearchComponent 会重新创建。每次都会渲染一个新的 myInput 迭代,并创建一个新的 SearchComponent

    但是如果你要在SearchComponent 中定义useState,那么只有SearchComponent 会重新渲染whens 状态更改,从而使原始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>
      );
    }
    

    【讨论】:

    • React 组件渲染不应该引起副作用,在函数组件中创建一个全新的组件肯定是副作用。这也使阅读变得非常困难。 SearchComponent 应该移出App 并接受它需要的任何props
    • @jwilson 我知道这一点,看起来 OP 也是如此。他测试了当他在函数之外提取组件时它是否有效。我的回答不是指出明显的最佳实践(OP 已经知道那是什么),而是试图帮助理解为什么该功能在当前构造中不能按预期工作。
    猜你喜欢
    • 2019-12-16
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    • 2022-06-12
    • 1970-01-01
    • 2021-08-03
    • 1970-01-01
    • 2020-03-05
    相关资源
    最近更新 更多