react 创建项目的两种方式
- 1.npm 全局安装
npm install -g create-react-app
create-react-app my-react-app
一般安装到了你的npm文件夹下
设置在系统的环境变量里面
- 2.npx 非全局安装
// 现将 my-react-app下载到本地,用完删除
npx create-react-app my-react-app
受控表单(受控组件)
什么是表单??
- 在React里,HTML表单元素的工作方式和其他的DOM元素有些不同,这是因为表单元素会保持一些内部的state.
- 例如这个纯 HTML 表单只接受一个名称:
<form>
<label>
名字:
<input type="text" name="name" />
</label>
<input type="submit" value="提交" />
</form>
- 此表单具有默认的 HTML 表单行为,即在用户提交表单后浏览到新页面。
- 如果你在 React 中执行相同的代码,它依然有效。
- 但大多数情况下,使用 JavaScript 函数可以很方便的处理表单的提交, 同时还可以访问用户填写的表单数据。实现这种效果的标准方式是使用
“受控组件”
。
什么是受控组件?
- 在 HTML 中,表单元素(如
<input>
、<textarea>
和<select>
)通常自己维护 state,并根据用户输入进行更新。 - 而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用
setState()
来更新。
input受控:
例1:如果我们想让前一个示例在提交时打印出名称
- 我们可以将表单写为受控组件:
import React, { Component } from 'react'
// 如何获取表单数据?????
// 获取值/存值
// 受控表单
// 可以设置默认值
// defaultValue
export default class App extends Component {
state={
username:"",
}
handleClick=(params) => {
// console.log(this.username);
console.log(this.state.username);
}
handleChange=(e) => {
// 默认传一个事件源
// 传参之后事件源跑哪里去了?作为里面的第二个参数传入
// 1-获取到表单中的值
let username = e.target.value
console.log(username);
// 2-存值
// 2-1.放对象里 this.username = e.target.value
// this.username = e.target.value
// 2-2.放状态里 this.username = e.target.value
this.setState({
username:e.target.value
})
// 为什么第二种好??
// 输入框本来是自己控制的
// 怎么设置成受我们控制,而不受浏览器控制
// 受控表单有初始value时,再输入就不受浏览器控制了
// 所以想要更新界面的话。就要使用改变状态的方式了,成为受我们控制的表单
}
render() {
return (
<div>
{/* 登录框的例子 */}
<label htmlFor="username">
用户名: <input type="text" id="username" value={this.state.username} onChange={this.handleChange}/>
</label>
<br></br>
<label htmlFor="password">
密码: <input type="password" id="password"/>
</label>
<br></br>
<button onClick={this.handleClick}>提交</button>
</div>
)
}
}
- 由于在表单元素上设置了
value
属性,因此显示的值将始终为this.state.value
,这使得 React 的 state 成为唯一数据源。 - 由于
handlechange
在每次按键时都会执行并更新 React 的 state,因此显示的值将随着用户输入而更新。 - 对于受控组件来说,输入的值始终由 React 的 state 驱动。
例2:合并多个输入
- 当需要处理多个
input
元素时,我们可以给每个元素添加name属性,并让处理函数根据event.target.name的值选择要执行的操作。 - 下面的是使用data属性,其实原理是一样的。
- 还想获取密码,需要在密码框中再定义一个相似的
onChange
事件,所以想把这两个相似的事件合并成一个事件就解决,获取不同输入框的不同的value值, - 这里使用了
data属性
,命名成了data-name
import React, { Component } from "react";
// 合并多个输入
export default class App extends Component {
state = {
username: "",
password: "",
};
handleClick = (params) => {
console.log(this.state.username, this.state.password);
};
// handleChange = (e) => {
// this.setState({
// username: e.target.value,
// });
// };
// 原来的密码框事件是叫这个handlePasswordChange
// handlePasswordChange = (e) => {
// this.setState({
// password: e.target.value,
// });
// };
// 两个函数合并成一个
// 传参 合并多个输入
// e.target.dataset.name
handleChange = (e) => {
this.setState({
[e.target.dataset.name]: e.target.value,
});
};
render() {
return (
<div>
<label htmlFor="username">
用户名:{" "}
<input
type="text"
id="username"
data-name="username"
value={this.state.username}
onChange={this.handleChange}
/>
</label>
<br></br>
<label htmlFor="password">
密码:{" "}
<input
type="password"
id="password"
data-name="password"
value={this.state.password}
onChange={this.handleChange}
/>
</label>
<br></br>
<button onClick={this.handleClick}>提交</button>
</div>
);
}
}
select受控:
- 在HTML中
<select>
<option value="grapefruit">葡萄柚</option>
<option value="lime">酸橙</option>
<option selected value="coconut">椰子</option>
<option value="mango">芒果</option>
</select>
- 请注意,由于
selected
属性的缘故,椰子选项默认被选中。 - React 并不会使用
selected
属性,而是在根select
标签上使用value
属性。这在受控组件中更便捷,因为您只需要在根标签中更新它。 - 例如:
import React, { Component } from 'react'
// select表单
// 怎么变为 受控表单
export default class App extends Component {
// 调用父类的初始化的方法
constructor(props){
super(props)
this.state={
selectValue:"中文",
}
}
handleChange=(e) => {
this.setState({
selectValue:e.target.value
})
}
render() {
return (
<div>
<select name="" id="" value={this.state.selectValue} onChange={this.handleChange}>
<option value="粤语">粤语</option>
<option value="德语">德语</option>
<option value="中文">中文</option>
</select>
</div>
)
}
}
- 总的来说,这使得,
<input type="text">
,<textarea>
和<select>
之类的标签都非常相似—它们都接受一个value
属性,你可以使用它来实现受控组件。
受控输入空值时!
非受控组件
文件 input 标签
- 在 HTML 中,
<input type="file">
允许用户从存储设备中选择一个或多个文件,将其上传到服务器,或通过使用 JavaScript 的 File API 进行控制。 - 因为它的 value 只读,所以它是 React 中的一个非受控组件。
<input type="file" />
- 在react中,执行下面的代码,会报错
import React, { Component } from "react";
export default class App extends Component {
state = {
value:"",
};
componentDidMount() {
document.getElementById("file").addEventListener("change", function (e) {
// 获取到上传文件的内容
console.log(e.target.files);
});
}
render() {
return (
<div>
<input type="file" name="" id="file" value={this.state.value} />
</div>
);
}
}
- 错
- 非受控表单
ref
获取dom节点
例子1:
import React, { Component } from "react";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {};
// 1- 创建了一个 ref
this.fileref = React.createRef();
}
componentDidMount() {
document.getElementById("file").addEventListener("change", function (e) {
// 获取到上传文件的内容
console.log(e.target.files);
});
}
handleClick = (e) => {
console.log(this.fileref.current.value);
};
render() {
return (
<div>
<input type="file" name="" id="file" ref={this.fileref}/>
<button onClick={this.handleClick}>获取dom节点</button>
</div>
);
}
}
例子2:输入框自动聚焦
import React, { Component } from 'react'
// 输入框自动聚焦
// 在挂载的时候,ref获取节点,给他onFous
export default class App extends Component {
constructor(props){
super(props)
this.inputRef = React.createRef()
}
componentDidMount() {
// document.getElementById("text").focus()
this.inputRef.current.focus()
}
render() {
return (
<div>
<input type="text" id="text" ref={this.inputRef}/>
</div>
)
}
}
- 因为非受控组件将真实数据储存在 DOM 节点中,所以在使用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码美观性,并且希望快速编写代码,使用非受控组件往往可以减少你的代码量。否则,你应该使用受控组件。