乐趣区

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 元素用于修改 user 的 name 属性,如果希望在页面刷新时,将 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 元素已经更新成 Edite,input 却没有变化:

这是因为,在 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>

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

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>
页面效果:

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>
页面效果:

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 使用方式和输入框一样。

退出移动版