react 初识记录(三)

106 阅读4分钟

​持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情 列表&Key

列表


function App() {
  const nums = [1,2,3,4,5]
  const listLi = nums.map((num) => <li key={num}>{num}</li>)
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
         <ul>{listLi}</ul>
      </header>
    </div>
  );
}

key

key帮助React识别哪些元素改变了,比如被添加或删除。因此要给数组中的每一个元素赋予一个确定的标识

一个元素的key最好是这个元素在列表中拥有的一个独一无二的字符串。通常,以数据中的id作为元素的key

当元素没有确定id的时候,用元素索引index作为key

用key提取组件

元素的key只有放在就近的数组上下文中才有意义

错误写法


function ListItem(props) {
  const value = props.value
  return(
      <li key={value.toString()}>{value}</li>
  )
}
function NumberList(props){
    const numbers = props.numbers;
    const listItems = numbers.map((number) =>
        <ListItem  value={number} />
    );
    return (
        <ul>{listItems}</ul>
    )
}

正确写法


function ListItem(props) {
  const value = props.value
  return(
      <li>{props.value}</li>
  )
}
function NumberList(props){
    const numbers = props.numbers;
    const listItems = numbers.map((number) =>
        <ListItem key={number.toString()}  value={number} />
    );
    return (
        <ul>{listItems}</ul>
    )
}

key值在兄弟节点之间必须唯一

数组元素中使用的key在其兄弟节点之间应该是独一无二的。然而,它们不需要是全局唯一的。当生成两个不同的数组时,可以使用相同的key值

key会传递信息给React,但不会传递给组件。组件需要使用key属性的值,需要用其他属性显式传递值

JSX中嵌入map()

JSX允许在大括号中嵌入任何表达式,所以可以内联map()返回结果


function NumberList(props){
    const numbers = props.numbers;
    return (
        <ul>{numbers.map((number)=>{
            <ListItem key={number.toString()} value={number}></ListItem>
        })}</ul>
    )
}

表单

在React里,HTML表单元素的工作方式和其他的DOM元素有些不同,这是因为表单元素通常会保持一些内部的state。纯HTML表单只接收一个名称:


    <form>
        <label>名称:
        <input type="text" name="name">
        </label>
        <input type="submit" value="提交">
    </form>

此表单具有默认的HTML表单行为,即在用户提交表单后跳转到新页面。在React中执行相同的代码,依旧有效,但大多数情况下,使用JavaScript函数可以很方便的处理表单的提交,同时还可以访问用户填写的表单数据。实现这种效果的标准方式是使用“受控组件

受控组件

在HTML中,表单元素(如、和)通常自己维护state,并根据用户输入进行更新。而在React中,可变状态通常保存在组件的state属性中,并且只能通过使用setState()来更新。


class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
​
  handleChange(event) {    this.setState({value: event.target.value});  }
  handleSubmit(event) {
    alert('提交的名字: ' + this.state.value);
    event.preventDefault();
  }
​
  render() {
    return (
      <form onSubmit={this.handleSubmit}>        <label>
          名字:
          <input type="text" value={this.state.value} onChange={this.handleChange} />        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}

受控组件输入的值始终由React的state驱动。

textarea标签

HTML中,元素通过其子元素定义:


<textarea>这里是文本</textarea>

React中,使用value属性代替。


class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: '',
    }
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
    this.setState({value: event.target.value});
}
handleSubmit(event) {
    alert('提交' + this.state.value);
    event.preventDefault();
}
render() {
    return (
        <div className="App">
            <form onSubmit={this.handleSubmit}>
                <label>
                    提交:
                    <input type="text" value={this.state.value} onChange={this.handleChange} />
                </label>
                <input type="submit" value="提交" />
            </form>
        </div>
    );
}
}

select标签

在HTML中,<select>创建下拉列表标签。

<select>
    <option value="a">a</option>
    <option selected  value="b">b</option>
</select>

由于selected属性的缘故,b默认被选择。React并不会使用selected属性,而是在根select标签上使用value属性。这在受控组件中更便捷,只需在根标签中更新。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 'a',
    }
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
    this.setState({value: event.target.value});
}
handleSubmit(event) {
    alert('提交' + this.state.value);
    event.preventDefault();
}
render() {
    return (
        <div className="App">
            <form onSubmit={this.handleSubmit}>
                <label>
                    提交:
                   <select value={this.state.value} onChange={this.handleChange}>
                       <option value="a">a</option>
                       <option value="b">b</option>
                   </select>
                </label>
                <input type="submit" value="提交" />
            </form>
        </div>
    );
}
}

总结:input,textarea和select之类得标签都非常相似,都是接收value属性。

文件input标签

HTML中js<input type="file">允许用户从存储设备中选择一个或多个文件,将其上传到服务器,或通过使用JavaScript的File API进行控制

<input type="file"/>

因为value是只读,所以是React中的一个非受控组件。

处理多个输入

当需要处理多个input元素时,可以给每个元素添加name属性,并让处理函数根据event.target.name的值选择要执行的操作。


class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isOn: true,
      nums: 2
    }
   this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
    this.setState({
[name]: value
    });
}
render() {
    return (
        <form>
            <label>
                参与:
                <input
                    name="isOn"
                    type="checkbox"
                    checked={this.state.isOn}
                    onChange={this.handleChange} />
            </label>
            <br />
            <label>
                数量:
                <input
                    name="nums"
                    type="number"
                    value={this.state.nums}
                    onChange={this.handleChange} />
            </label>
        </form>
    )
}
}

这里使用了ES6计算属性名称的语法更新给定输入名称对应的state值:


this.setState({
​
[name]: value
​
})

等同ES5

var state = {};

state[name] = value;

this.setState(state);

另外由于setState()自动将部分state合并到当前state,只需调用它更改部分state即可。

受控输入空值

在受控组件上指定value的prop会阻止用户更改输入。如果指定value,但输入仍可编辑,则可能是将value设置为undefined或null。

受控组件的替代品

有时使用受控组件会很麻烦,因为需要为数据变化的每种方式都编写事件处理函数,并通过一个React组件传递所有输入state。这时就需要到非受控组件

非受控组件

在大多数情况下,都是使用受控组件来处理表单数据。在一个受控组件中,表单数据是由React组件来管理的。另一种替代方案就是使用非受控组件,非受控组件中,表单数据将交由DOM节点来进行处理。

编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,使用ref来从DOM节点中获取表单数据。

class App extends React.Component {
  constructor(props) {
      super(props);
      this.handleSubmit = this.handleSubmit.bind(this);
      this.input = React.createRef();
  }
  handleSubmit(event){
      alert('aa'+this.input.current.value);
      event.preventDefault();
  }
  render() {
      return (
          <form onSubmit={this.handleSubmit}>
              <label>
                  姓名:
                  <input type="text" ref={this.input}></input>
              </label>
              <input type="submit" value="提交"></input>
          </form>
      )
  }
}

非受控组件将真实数据存储在DOM节点中,所以在使用非受控组件能更容易同时集成React和非React代码。