React之非受控组件

Input 输入框

react 中,表单元素的表现形式和其他标准元素有所不同,它除了可以表现一些数据以外,还可以用来接收用户的输入:

import React, { Component } from "react"
import ReactDOM from "react-dom"

class Forms extends Component {

  state = {
    name: "Sara"
  };

  render() {
    const { name } = this.state;
    return (
      <div>
        <ul>
          <li>name: {name}</li>
        </ul>
        <hr />
        <div>
          <input type="text" />
          <button>save</button>
        </div>
      </div>
    );
  }
}

ReactDOM.render(<Forms />, document.querySelector("#root"))

在该示例中,input元素用于修改username属性,如果希望在页面刷新时,将name的值填充在input元素中,我们可以使用input提供的defaultValue,为其设置默认值:

<input type="text" defaultValue={name} />

这时,输入框中就会显示Sara的值。接下来,当用户点击save按钮时,我们修改name的值为Edite

  ...
  // 增加 save 方法
  save = () => {
    this.setState({
      name: "Edite"
    })
  }
  
  ...
  // 绑定
  <button onClick={this.save}>save</button>

当用户点击按钮时,save方法调用,我们通过setState修改name的值,这时,state更新会触发view的更新,可是,我们看到li元素已经更新成Editeinput却没有变化:

《React之非受控组件》

这是因为,在react中,将组件分成了受控组件非受控组件,所谓受控,就是指当state更新时,组件会被更新。表单组件都是非受控组件,这也就意味着当state更新时,这些组件中的状态不会被更新。因此,如果希望将受控组件变成非受控组件的话,我们就要为其设置value的属性:

<input type="text" value={name} />

当再次点击save按钮时,可以看到,input控件中,显示了最新的name,可是,当用户再次输入的时候,输入框中的值却不会发生变化了,因为input这时已经是一个受控组件,根据react渲染思路,只有当state发生更新的时候,view才会更新,所以在这里,我们需要给input绑定onChange事件,监听用户的输入,当输入发生时,使用setState方法更新state

nameInputChange = () => {

}
...
<input type="text" value={name} onChange={this.nameInputChange} />

下一步,在nameInputChange调用时,获取用户输入的值。这时,就涉及到真实节点的访问,有两种方式可以获取真实节点:

// 第一种方式:使用 event 对象
nameInputChange = e => {
    const text = e.target.value;
}

第一种方式,可以通过event.target直接访问真实节点,从而获取用户输入的值。

// 第二种方式:使用 React 引用
textInput = React.createRef();
nameInputChange = e => {
    const text = this.textInput.current.value;
}

// 将引用绑定在元素上
<input
    ref={this.nameInputChange}
    type="text"
    value={name}
    onChange={this.nameInputChange} />

第二种方式,使用React引用。React.createRef可以创建一个React引用,然后将其绑定到需要访问的元素上。

以上两种方式都可以用来获取真实节点。拿到用户输入的值之后,再通过setState完成更新。以下是完整代码:

import React, { Component } from "react";
import ReactDOM from "react-dom";

class Forms extends Component {

  state = {
    name: "Sara"
  };

  save = () => {
    this.setState({
      name: "Edite"
    })
  };

  textInput = React.createRef();

  nameInputChange = e => {
    const text = this.textInput.current.value;
    this.setState({
      name: text
    });
  };

  render() {
    const { name } = this.state;
    return (
      <div>
        <ul>
          <li>name: {name}</li>
        </ul>
        <hr />
        <div>
          <input
            ref={this.textInput}
            type="text"
            value={name}
            onChange={this.nameInputChange} />
          <button onClick={this.save}>save</button>
        </div>
      </div>
    );
  }
}

ReactDOM.render(<Forms />, document.querySelector("#root"));

Input 单选框

首先添加单选框数据:

const genders = [{
  id: 1,
  text: "男",
  value: "male"
}, {
  id: 2,
  text: "女",
  value: "female"
}];

class Forms extends Component {
    
    state = {
        name: "Sara",
        gender: "male" // 添加性别
    };

    ...
}

genders是一组单选框数据,用来表示用户的性别。接下来,我们在Forms组件中将其渲染出来:

...
// jsx
<div>
    性别:
    {
        genders.map(item => (
            <label key={item.id}>
                <input
                    name="gender"
                    value={item.value}
                    type="radio"
                    />{item.text}
            </label>
        ))
    }
</div>
...

以上代码会在页面上添加一组单选按钮:

《React之非受控组件》

radio也属于非受控组件,它和input不同的是,它是通过checked属性控制。因此,在渲染的时候,我们要对其状态进行判断:

// jsx
<div>
    性别:
    {
        genders.map(item => (
            <label key={item.id}>
                <input
                    checked={this.state.gender === item.value} // 添加此处
                    name="gender"
                    value={item.value}
                    type="radio"
                    />{item.text}
            </label>
        ))
    }
</div>

当添加checked属性之后,radio就从非受控组件变成受控组件,这时,还需要使用onChange事件来处理用户的操作:

// jsx
<div>
    性别:
    {
        genders.map(item => (
            <label key={item.id}>
                <input
                    checked={this.state.gender === item.value}
                    name="gender"
                    value={item.value}
                    type="radio"
                    onChange={() => {    
                        this.setState({
                            gender: item.value
                        });
                    }}
                    />{item.text}
            </label>
        ))
    }
</div>

完整代码:

import React, { Component } from "react";
import ReactDOM from "react-dom";

const genders = [{
  id: 1,
  text: "男",
  value: "male"
}, {
  id: 2,
  text: "女",
  value: "female"
}];

class Forms extends Component {

  state = {
    name: "Sara",
    gender: "male"
  };

  save = () => {
    this.setState({
      name: "Edite",
    })
  };

  textInput = React.createRef();

  nameInputChange = e => {
    const text = this.textInput.current.value;
    this.setState({
      name: text
    });
  };

  render() {
    const { name, gender } = this.state;
    return (
      <div>
        <ul>
          <li>name: {name}</li>
          <li>gender: {gender}</li>
        </ul>
        <hr />
        <div>
          <input
            ref={this.textInput}
            type="text"
            value={name}
            onChange={this.nameInputChange} />
          <button onClick={this.save}>save</button>
        </div>
        <hr />
        <div>
          性别:
          {
            genders.map(item => (
              <label key={item.id}>
                <input
                  checked={this.state.gender === item.value}
                  name="gender"
                  value={item.value}
                  type="radio"
                  onChange={() => {
                    this.setState({
                      gender: item.value
                    });
                  }}
                />{item.text}
              </label>
            ))
          }
        </div>
      </div>
    );
  }
}

ReactDOM.render(<Forms />, document.querySelector("#root"));

Input 多选框

添加多选框数据:

// 所有兴趣可选项
const hobbies = [{
  id: 1,
  text: "HTML",
  value: "HTML"
}, {
  id: 2,
  text: "CSS",
  value: "CSS"
}, {
  id: 3,
  text: "JAVASCRIPT",
  value: "JAVASCRIPT"
}];

class Forms extends Component {
    
    state = {
        name: "Sara",
        gender: "male",
        hobbies: ["HTML", "CSS"]  // 已选兴趣
    };

    ...
}

hobbies是一组多选框数据,用来表示用户的兴趣。页面渲染:

// jsx
<div>
    兴趣:
    {
        hobbies.map(item => {
            return (
                <label key={item.id}>
                    <input
                        type="checkbox"
                        name="hobby"
                        value={item.value}
                        />{item.text}
                </label>
            );
        })
    }
</div>

页面效果:

《React之非受控组件》

checkbox也是通过checked属性控制元素的表现,因为它是多个数据的集合,所以我们要对每一个选项都进行判断:

// 判断当前值是否被选中
isHobby = hobby => this.state.hobbies.some(item => item === hobby.value);

// jsx
<div>
    兴趣:
    {
        hobbies.map(item => {
            return (
                <label key={item.id}>
                    <input
                        checked={this.isHobby(item)} // 添加此处
                        type="checkbox"
                        name="hobby"
                        value={item.value}
                        />{item.text}
                </label>
            );
        })
    }
</div>

isHobby方法用来判断当前选项是否被用户选中。接着添加onChange事件:

<div>
    兴趣:
    {
        hobbies.map(item => {
            return (
                <label key={item.id}>
                    <input
                        onChange={e => {
                            ...
                        }}
                        checked={this.isHobby(item)}
                        type="checkbox"
                        name="hobby"
                        value={item.value}
                        />{item.text}
                </label>
            );
        })
    }
</div>

当用户进行多选的时候,首先我们需要知道用户的操作类型,是 选中 还是 取消 当前选项,这里可以通过e.target.checked来判断,当该值为true标志用户 选中,否则就是 取消。然后在根据这个类型,来操作this.state.hobbies,这里我们封装一个函数来处理:

// 多选状态的处理
setHobby = (checked, value) => {
    let hobbies;
    if (checked) {
        hobbies = [...this.state.hobbies, value];
    } else {
        hobbies = this.state.hobbies.filter(item => item !== value)
    }
    this.setState({
        hobbies
    });
}

// jsx
<div>
    兴趣:
    {
        hobbies.map(item => {
            return (
                <label key={item.id}>
                    <input
                        onChange={e => {
                            this.setHobby(e.target.checked, item.value); // 添加此处
                        }}
                        checked={this.isHobby(item)}
                        type="checkbox"
                        name="hobby"
                        value={item.value}
                        />{item.text}
                </label>
            );
        })
    }
</div>

setHobby方法接收两个状态值,分别表示用户的选中状态和选项值,函数内部通过对状态值的判断,对数组进行增加或删除操作。

完整代码:

import React, { Component } from "react";
import ReactDOM from "react-dom";

const genders = [{
  id: 1,
  text: "男",
  value: "male"
}, {
  id: 2,
  text: "女",
  value: "female"
}];

const hobbies = [{
  id: 1,
  text: "HTML",
  value: "HTML"
}, {
  id: 2,
  text: "CSS",
  value: "CSS"
}, {
  id: 3,
  text: "JAVASCRIPT",
  value: "JAVASCRIPT"
}];

class Forms extends Component {

  state = {
    name: "Sara",
    gender: "male",
    hobbies: ["HTML", "CSS"]
  };

  save = () => {
    this.setState({
      name: "Edite",
    })
  };

  textInput = React.createRef();

  nameInputChange = e => {
    const text = this.textInput.current.value;
    this.setState({
      name: text
    });
  };

  isHobby = hobby => this.state.hobbies.some(item => item === hobby.value);

  setHobby = (checked, value) => {
    let hobbies;
    if (checked) {
      hobbies = [...this.state.hobbies, value];
    } else {
      hobbies = this.state.hobbies.filter(item => item !== value)
    }
    this.setState({
      hobbies
    })
  }

  render() {
    const { name, gender } = this.state;
    return (
      <div>
        <ul>
          <li>name: {name}</li>
          <li>gender: {gender}</li>
          <li>兴趣:{this.state.hobbies.toString()}</li>
        </ul>
        <hr />
        <div>
          <input
            ref={this.textInput}
            type="text"
            value={name}
            onChange={this.nameInputChange} />
          <button onClick={this.save}>save</button>
        </div>
        <hr />
        <div>
          性别:
          {
            genders.map(item => (
              <label key={item.id}>
                <input
                  checked={this.state.gender === item.value}
                  name="gender"
                  value={item.value}
                  type="radio"
                  onChange={() => {
                    this.setState({
                      gender: item.value
                    });
                  }}
                />{item.text}
              </label>
            ))
          }
        </div>
        <hr />
        <div>
          兴趣:
          {
            hobbies.map(item => {
              return (
                <label key={item.id}>
                  <input
                    onChange={e => {
                      this.setHobby(e.target.checked, item.value);
                    }}
                    checked={this.isHobby(item)}
                    type="checkbox"
                    name="hobby"
                    value={item.value}
                  />{item.text}
                </label>
              );
            })
          }
        </div>
      </div>
    );
  }
}

ReactDOM.render(<Forms />, document.querySelector("#root"));

Select 单选框

添加cities数据:

const cities = [{
  id: 1,
  text: "成都",
  value: "chengdu"
}, {
  id: 2,
  text: "北京",
  value: "beijing"
}, {
  id: 3,
  text: "广州",
  value: "guangzhou"
}];

class Forms extends Component {
    
    state = {
        name: "Sara",
        gender: "male",
        hobbies: ["HTML", "CSS"],
        city: "beijing",
    };

    ...
}

cities集合用来表示可选的城市列表。页面渲染:

<div>
    出生地:
    <select
        value={this.state.city}
        onChange={() => {
            ...
        }}
        >
        {
            cities.map(item => {
                return (
                    <option
                        key={item.id}
                        value={item.value}>{item.text}</option>
                );
            })
        }
    </select>
</div>

页面效果:

《React之非受控组件》

select是用value控制显示,因此使用方法和input输入框一样:

// 创建 React 引用
citySelect = React.createRef();

// jsx
<div>
    出生地:
    <select
        ref={this.citySelect}
        value={this.state.city}
        onChange={() => {
            this.setState({
                city: this.citySelect.current.value
            });
        }}
        >
        {
            cities.map(item => {
                return (
                    <option
                        key={item.id}
                        value={item.value}>{item.text}</option>
                );
            })
        }
    </select>
</div>

完整代码:

import React, { Component } from "react";
import ReactDOM from "react-dom";

const genders = [{
  id: 1,
  text: "男",
  value: "male"
}, {
  id: 2,
  text: "女",
  value: "female"
}];

const hobbies = [{
  id: 1,
  text: "HTML",
  value: "HTML"
}, {
  id: 2,
  text: "CSS",
  value: "CSS"
}, {
  id: 3,
  text: "JAVASCRIPT",
  value: "JAVASCRIPT"
}];

const cities = [{
  id: 1,
  text: "成都",
  value: "chengdu"
}, {
  id: 2,
  text: "北京",
  value: "beijing"
}, {
  id: 3,
  text: "广州",
  value: "guangzhou"
}];

class Forms extends Component {

  state = {
    name: "Sara",
    gender: "male",
    hobbies: ["HTML", "CSS"],
    city: "beijing",
  };

  save = () => {
    this.setState({
      name: "Edite",
    })
  };

  textInput = React.createRef();
  citySelect = React.createRef();

  nameInputChange = e => {
    const text = this.textInput.current.value;
    this.setState({
      name: text
    });
  };

  isHobby = hobby => this.state.hobbies.some(item => item === hobby.value);

  setHobby = (checked, value) => {
    let hobbies;
    if (checked) {
      hobbies = [...this.state.hobbies, value];
    } else {
      hobbies = this.state.hobbies.filter(item => item !== value)
    }
    this.setState({
      hobbies
    })
  }

  render() {
    const { name, gender } = this.state;
    return (
      <div>
        <ul>
          <li>name: {name}</li>
          <li>gender: {gender}</li>
          <li>兴趣:{this.state.hobbies.toString()}</li>
          <li>出生地:{this.state.city}</li>
        </ul>
        <hr />
        <div>
          <input
            ref={this.textInput}
            type="text"
            value={name}
            onChange={this.nameInputChange} />
          <button onClick={this.save}>save</button>
        </div>
        <hr />
        <div>
          性别:
          {
            genders.map(item => (
              <label key={item.id}>
                <input
                  checked={this.state.gender === item.value}
                  name="gender"
                  value={item.value}
                  type="radio"
                  onChange={() => {
                    this.setState({
                      gender: item.value
                    });
                  }}
                />{item.text}
              </label>
            ))
          }
        </div>
        <hr />
        <div>
          兴趣:
          {
            hobbies.map(item => {
              return (
                <label key={item.id}>
                  <input
                    onChange={e => {
                      this.setHobby(e.target.checked, item.value);
                    }}
                    checked={this.isHobby(item)}
                    type="checkbox"
                    name="hobby"
                    value={item.value}
                  />{item.text}
                </label>
              );
            })
          }
        </div>
        <hr />
        <div>
          出生地:
          <select
            ref={this.citySelect}
            value={this.state.city}
            onChange={() => {
              this.setState({
                city: this.citySelect.current.value
              });
            }}
          >
            {
              cities.map(item => {
                return (
                  <option
                    key={item.id}
                    value={item.value}>{item.text}</option>
                );
              })
            }
          </select>
        </div>
      </div>
    );
  }
}

ReactDOM.render(<Forms />, document.querySelector("#root"));

Textarea

textarea使用方式和输入框一样。

    原文作者:佛也要生活
    原文地址: https://segmentfault.com/a/1190000017773782
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞