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

问题描述 投票:0回答:3

我是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>
)}
reactjs react-hooks
3个回答
13
投票

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
投票

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

1
投票

发生这种情况是因为

useState
钩子不是“钩”到您的
SearchComponent
,而是您的
MyInput
组件。每当您调用
updateCitySearch()
时,您都会更改
MyInput
的状态,从而强制 整个 组件重新渲染。

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()
,App 组件重新渲染并重新创建
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>
  );
}
© www.soinside.com 2019 - 2024. All rights reserved.