如何使用React hooks实现受控组件教程

1,092 阅读4分钟

!

受控组件,Hooks方式

React提供了2种方法来访问输入字段的值:使用受控组件或不受控组件技术。我更喜欢受控组件,因为你通过组件的状态读取和设置输入值。

在这篇文章中,你将读到如何使用React钩子实现受控组件。

1.受控组件

假设你有一个简单的文本输入域,你想访问它的值。

import { useState } from 'react';
function MyControlledInput({ }) {
  const [value, setValue] = useState('');
  const onChange = (event) => {
    setValue(event.target.value);
  };
  return (
    <>
      <div>Input value: {value}</div>
      <input value={value} onChange={onChange} />
    </>
  );
}

打开演示,在输入栏里输入。你可以看到,value 状态变量包含了输入到输入框中的值,而且每次你输入新的值时,它也会更新。

输入字段被控制了,因为React从状态<input value={value} ... /> 中设置它的值。当用户在输入框中输入时,onChange 处理程序会用从事件对象中获取的输入值更新状态:event.target.value

value state变量是真理的来源。每次你需要访问用户在输入框中输入的值时--只要读取 状态变量。value

受控组件方法可以帮助你访问任何输入类型的值:是普通的文本输入,文本区,选择字段。

2.受控组件的3个步骤

设置受控组件需要3个步骤。

  1. 定义要保存输入值的状态:const [value, setValue] = useState('')

  2. 创建事件处理程序,当输入值发生变化时更新状态。

const onChange = event => setValue(event.target.value);
  1. 给输入字段分配状态值,并附加事件处理程序:<input type="text" value={value} onChange={onChange} />

3.作为真理之源的状态

让我们看一个更复杂的例子。一个网页包括一个雇员的名字的列表。你需要添加一个输入字段,当用户在这个字段中输入时,雇员列表会被按名字过滤。

这是一个使用受控输入的好场景。下面是一个可能的实现。

function FilteredEmployeesList({ employees }) {
  const [query, setQuery] = useState('');
  
  const onChange = event => setQuery(event.target.value);
  const filteredEmployees = employees.filter(name => {
    return name.toLowerCase().includes(query.toLowerCase());
  });
  return (
    <div>
      <h2>Employees List</h2>
      <input 
        type="text" 
        value={query} 
        onChange={onChange}
      />
      <div className="list">
        {filteredEmployees.map(name => <div>{name}</div>)}
      </div>
    </div>
  );
}

打开演示,在输入栏中输入一个查询。你会看到员工列表是如何被过滤的。

重要的是,query 状态变量是输入字段中输入值的真实来源。你在employees.filter() 里面使用它来过滤雇员列表:name.toLowerCase().includes(query)

4.对受控输入进行降压

在前面的实现中,只要你在输入框中输入一个字符,列表就会被立即过滤掉。这并不总是很方便,因为它在输入查询时分散了用户的注意力。

让我们用去跳的方式来改善用户体验:在最后一次输入变化后,以400毫秒的延迟来过滤列表。

让我们来看看一个可能的去跳控制输入的实现。

import { useDebouncedValue } from './useDebouncedValue';
function FilteredEmployeesList({ employees }) {
  const [query, setQuery] = useState('');
  const debouncedQuery = useDebouncedValue(query, 400);
  
  const onChange = event => setQuery(event.target.value);
  const filteredEmployees = employees.filter(name => {
    return name.toLowerCase().includes(debouncedQuery.toLowerCase());
  });
  return (
    <div>
      <h2>Employees List</h2>
      <input 
        type="text" 
        value={query} 
        onChange={onChange}
      />
      <div className="list">
        {filteredEmployees.map(name => <div>{name}</div>)}
      </div>
    </div>
  );
}

打开演示,然后在输入栏中输入一个查询。雇员列表不会在你输入时过滤,而是在最近一次按键后经过400ms后过滤。

新的状态值debouncedQuery 值由一个专门的钩子管理,该钩子实现了debouncing:useDebouncedValue(query, 400)debouncedQuery 状态值用于过滤员工列表,并从输入值状态中导出。

下面是useDebouncedValue() 的实现。

export function useDebouncedValue(value, wait) {
  const [debouncedValue, setDebouncedValue] = useState(value);
  useEffect(() => {
    const id = setTimeout(() => setDebouncedValue(value), wait);
    return () => clearTimeout(id);
  }, [value]);
  return debouncedValue;
}

用几句话来说,它是如何工作的。

首先,useDebouncedValue() 钩子创建一个源自主状态的新状态。

然后,useEffect()wait 延迟后更新debouncedValue 状态,当主value 状态改变时。

5.总结

受控组件是一种方便的技术,用于访问React中输入字段的值。它不使用引用,作为一个单一的真理来源来访问输入值。

设置一个受控输入需要3个步骤:

  1. 创建保存输入值的状态。[val, setVal] = useState('')
  • 定义事件处理程序,当用户在输入时更新状态。onChange = event => setVal(event.target.value)
  • 附加事件处理程序并在输入字段上设置value 属性:<input onChange={onChange} value={val} />

输入值状态的跳转需要使用专门的钩子创建一个新的派生状态debouncedQuery = useDebouncedValue(value, wait)