React 怎么更新/重置子组件数据

420 阅读2分钟

给组件添加key属性,重置时更新key

适用于:整个组件的重置,包含组件的state数据

如一个用户邮箱输入组件,从父组件接受初始值,组件内部可以重新输入。

// EmailInput 组件
const EmailInput: React.FC<IProp> = props => {
  const [email, setEmail] = useState(props.defaultEmail);
  
  const handleChange = event => {
    setEmail(event.target.value);
  };
  
  return <input onChange={handleChange} value={email} />;
}

此时,如果希望在父组件中可以切换不同的用户,切换后输入框需重置为当前用户的默认邮箱。我们可以使用 key 这个特殊的 React 属性。当 key 变化时, React 会创建一个新的而不是更新一个既有的组件。

<EmailInput
  defaultEmail={user.email}
  key={user.id}
/>

大部分情况下,这是处理重置 state 的最好的办法

如果某些情况下 key 不起作用,或者不太合适(如组件初始化的开销太大),又或者是我们只需要更新组件部分数据,可以考虑使用下面2种方式

根据props属性变更,更新数据

// EmailInput 组件
const EmailInput: React.FC<IProp> = props => {
  const [email, setEmail] = useState(props.email);
  
  useEffect(() => {
    setEmail(props.email);
  }, [props.id])
  
  // ...
}

有些时候,我们没有合适的props属性来作为更新的依赖,也想重新创建组件。一种解决方案是给一个随机值或者递增的值当作 props 的值。

使用实例方法重置数据

在组件内部,定义相关的重置方法,然后父组件使用 ref 获取组件实例来调用这个方法。

子组件:通过 forwardRefuseImperativeHandle 抛出内部方法

// EmailInput 组件
const EmailInput = forwardRef((props, ref) => {
  const [email, setEmail] = useState(props.email);
  
  const resetEmail = newEmail => {
    setEmail(newEmail);
  };
  
  // 对父组件抛出内部方法
  useImperativeHandle(ref, () => ({
    resetEmail
  }));
  
  // ...
})

父组件:命令式调用组件内部方法

// 父组件
const FormInput: React.FC = () => {
  const emailRef = useRef();
  // ...
  
  // 父组件调用自组件内部方法
  const setEmail = (email) => {
      emailRef.current.resetEmail(email);
  }
  
  return <EmailInput ref={emailRef} email={user.email} />
}

React 的思想是数据驱动视图,虽然通过这种方法也可以实现这种功能,不过还是更建议使用上面的2种方式。

总结:

对于非受控的组件,当想在 prop 变化时重置 state 的话,可以选择以下几种方式:

  • 重置内部所有的初始 state,使用 key 属性
  • 仅更改某些字段,观察特殊属性的变化(比如 props.userID)。
  • 使用 ref 调用实例方法。