React 传递钩子会导致重新渲染并失去对输入的关注

Sun*_*tva 2 javascript reactjs react-hooks

我有一个父组件,我在其中初始化了一些状态,然后我将其传递给子组件,以便他们可以更新它。然而,当更新被触发时,组件树被重新渲染并且我的输入失去焦点。添加一个key没有帮助。

// App.tsx

export function App(props) {
  const useVal = useState("");

  return (
    <Router>
      <Switch>
        <Route
          exact
          path="/"
          component={() => (
            <StartScreen
              useVal={useVal}
            />
          )}
        />
        // ...
    </Router>
  );
}
Run Code Online (Sandbox Code Playgroud)
// StartScreen.tsx

interface StartScreenProps {
  useVal: [string, React.Dispatch<React.SetStateAction<string>>];
}

function bindState<T>(
  [value, setState]: [T, React.Dispatch<React.SetStateAction<T>>]
) {
  return {
    value,
    onChange: ({ value }: { value: T }) => setState(value)
  }
}

export const StartScreen = (props: StartScreenProps) => {
  return (
    <form>
      <InputField
        key="myInput"
        {...bindState(props.useVal)}
      />
    </form>
  );
}
Run Code Online (Sandbox Code Playgroud)

因此,现在当我开始在 my InputField(基本上是 上的包装器<input>)上StartScreen.tsx输入时,输入不断失去焦点,因为组件完全重新渲染(我可以在 DOM 中看到它)。

Moh*_*ami 5

发生这种情况是因为您正在将一个函数传递给Routecomponent道具(我假设您正在使用react-router-dom):

文档

如果您为组件 prop 提供内联函数,您将在每次渲染时创建一个新组件。这会导致卸载现有组件并安装新组件,而不仅仅是更新现有组件。


要解决此问题,请使用render道具:

    <Route
      exact
      path="/"
      render={() => (
        <StartScreen
          useVal={useVal}
        />
      )}
    />
Run Code Online (Sandbox Code Playgroud)

这允许方便的内联渲染和包装,而无需上面解释的不需要的重新安装。