React 组件
创建组件
组件分为两类,分别是函数式组件,以及类组件
函数式组件
函数式组件中的 this
babel 官网的试一试,可以把函数复制进来看一看
类组件
类中的一般方法放到了类的原型对象上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <script type="text/babel"> class MyComponent extends React.Component { render() { console.log("render中的this:", this); return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>; } } ReactDOM.render(<MyComponent />, document.getElementById("test"));
</script>
|
组件三大特征
state
首先设置组件的 state
,进行状态的初始化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <script type="text/babel"> class Weather extends React.Component { constructor(props) { super(props); this.state = { isHot: true, }; } render() { const { isHot } = this.state; return <h1>今天天气很{isHot ? "炎热" : "凉爽"}</h1>; } } ReactDOM.render(<Weather />, document.querySelector("#test")); </script>
|
添加点击事件:
类中的方法默认开启了局部的严格模式
setState
状态不可以直接更改,必须要借助一个内置的 API:setState({})
,要求必须传递一个对象,而且是合并操作
复杂模式的修改,理解一下this
和其他的概念
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <script type="text/babel"> class Weather extends React.Component{
constructor(props){ console.log('constructor'); super(props) this.state = {isHot:false,wind:'微风'} this.changeWeather = this.changeWeather.bind(this) }
render(){ console.log('render'); const {isHot,wind} = this.state return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1> }
changeWeather(){
console.log('changeWeather'); const isHot = this.state.isHot this.setState({isHot:!isHot}) console.log(this);
} } ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
|
在开发中很少使用到构造函数,所以,属性和方法的设置,类似下面的代码块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script type="text/babel"> class Weather extends React.Component{ state = {isHot:false,wind:'微风'}
render(){ const {isHot,wind} = this.state return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1> }
changeWeather = () => { const isHot = this.state.isHot this.setState({isHot:!isHot}) } } ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
|
总结一下:
- 组件中
render
方法中的this
为组件实例对象
- 组件自定义的方法中
this
为undefined
,如何解决?
a). 强制绑定 this: 通过函数对象的bind()
b). 箭头函数
- 状态数据,不能直接修改或更新
props
基本传递
外部往组件中带东西
批量传递
而且 ...obj
在 babel
和 react 环境
下,只有在标签上才可以,如果你想输出的话是不可以的。
函数式组件的传值
对 Props 进行限制【类式组件】
通过引入新的库 prop-types.js
,引入完之后,全局中会多出个新的对象,叫做:PropTypes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class Person extends React.Component { render() { const { name, age, sex } = this.props; return ( <ul> <li>姓名:{name}</li> <li>性别:{sex}</li> <li>年龄:{age + 1}</li> </ul> ); } }
Person.propTypes = { name: PropTypes.string.isRequired, sex: PropTypes.string, age: PropTypes.number, speak: PropTypes.func, };
Person.defaultProps = { sex: "男", age: 18, };
|
对 Props 进行限制【函数式组件】
对 prop
的限制,也就是给这个类填上些属性
refs
字符串形式的 refs (不推荐使用)
通过给 ref
属性,可以给标签添加标记,比方说下面 handle1
方法中通过 refs
拿到 input 原生DOM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <script type="text/babel"> class Demo extends React.Component { handle1 = () => { console.log(this); const { inp1 } = this.refs; alert(inp1.value); }; render() { return ( <div> <input ref="inp1" type="text" /> <button onClick={this.handle1}>点我</button> </div> ); } } ReactDOM.render(<Demo />, document.querySelector("#test")); </script>
|
打开控制台看一下
回调 ref
基本使用
react
会帮你调用你在 ref
中定义的函数,并且把当前的标签节点作为形参传入函数中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <script type="text/babel"> class Demo extends React.Component { handle1 = () => { const { inp1 } = this; alert(inp1.value); }; render() { return ( <div> <input type="text" ref={(c) => (this.inp1 = c)} /> <button onClick={this.handle1}>点击</button> </div> ); } } ReactDOM.render(<Demo />, document.getElementById("test")); </script>
|
调用次数
如果你用内联函数的话,那么在组件更新的时候会调用两次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <script type="text/babel"> class Demo extends React.Component { state = { isHot: false, };
handle1 = () => { const { inp1 } = this; alert(inp1.value); };
handleChangeWeather = () => { const { isHot } = this.state; this.setState({ isHot: !isHot, }); };
render() { const { isHot } = this.state; return ( <div> <h1>今天天气很{isHot ? "炎热" : "凉爽"}</h1> <input type="text" ref={(c) => {this.inp1 = c; console.log("回调ref:>>", c);}} /> <br /> <button onClick={this.handle1}>点我获取</button> <button onClick={this.handleChangeWeather}>点我切换天气</button> </div> ); } } ReactDOM.render(<Demo />, document.getElementById("test")); </script>
|
代码执行后的效果如下图所示:
这个在官方文档上也有说明,拉倒最底下
官方说如果是内联函数的话,那么在每次渲染的时候又会创建新的函数实例,解决的办法就是绑定好了,别让它创建即可
修改后的代码效果如下:
createRef API (官方推荐的方式)
通过调用 React.createRef()
来创建一个 ref
的容器,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <script type="text/babel"> class Demo extends React.Component{
myRef = React.createRef() myRef2 = React.createRef() showData = ()=>{ alert(this.myRef.current.value); } showData2 = ()=>{ alert(this.myRef2.current.value); } render(){ return( <div> <input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/> <button onClick={this.showData}>点我提示左侧的数据</button> <input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="失去焦点提示数据"/> </div> ) } } ReactDOM.render(<Demo a="1" b="2"/>,document.getElementById('test')) </script>
|
事件处理
1 2 3 4
| (1).通过onXxx属性指定事件处理函数(注意大小写) a.React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —————— 为了更好的兼容性 b.React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————————为了更高效 (2).通过event.target得到发生事件的DOM元素对象 ——————————不要过度使用ref
|
非受控组件 & 受控组件
包含表单的组件会分类为
- 非受控组件:输入类的
dom
(比方说 input
、checkbox
、radio
等)是现用现取的
- 受控组件(推荐使用):输入类的
dom
,通过 state
维护,使用的时候从 state
中获取,(类似vue
中的 v-model
)
其中非受控组件的例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <script type="text/babel"> class Login extends React.Component{ handleSubmit = (event)=>{ event.preventDefault() const {username,password} = this alert(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`) } render(){ return( <form onSubmit={this.handleSubmit}> 用户名:<input ref={c => this.username = c} type="text" name="username"/> 密码:<input ref={c => this.password = c} type="password" name="password"/> <button>登录</button> </form> ) } } ReactDOM.render(<Login/>,document.getElementById('test')) </script>
|
event.preventDefault()
// 阻止表单提交,阻止一些默认的行为
受控组件的例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <script type="text/babel"> class Demo extends React.Component { state = { username: "", password: "", };
setUserName = (e) => { this.setState({ username: e.target.value, }); };
setPassword = (e) => { this.setState({ password: e.target.value, }); };
handleSubmit = (e) => { e.preventDefault(); const { username, password } = this.state; alert(`${username}, ${password}`); };
render() { return ( <form action="" onSubmit={this.handleSubmit}> 用户名: <input type="text" onChange={this.setUserName} name="username" /> 密码: <input type="password" onChange={this.setPassword} name="password" /> <button>登录</button> </form> ); } } ReactDOM.render(<Demo />, document.querySelector("#test")); </script>
|
高阶函数 & 函数柯里化
问题场景:
还是上面的例子,如果我想通过受控组件,维护多个 Form
的字段
比方说,我们是注册组件,需要保存用户名,密码,确认密码,性别,地址等等多字段
我们不可能写多个 save
函数为每一个字段去做状态的保存,而是通过统一的函数去做状态的保存
下面的截图中 saveFormData
就是高阶函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
class Login extends React.Component { state = { username: "", password: "", };
saveFormData = (dataType) => { return (event) => { this.setState({ [dataType]: event.target.value }); }; };
handleSubmit = (event) => { event.preventDefault(); const { username, password } = this.state; alert(`你输入的用户名是:${username},你输入的密码是:${password}`); }; render() { return ( <form onSubmit={this.handleSubmit}> 用户名: <input onChange={this.saveFormData("username")} type="text" name="username" /> 密码: <input onChange={this.saveFormData("password")} type="password" name="password" /> <button>登录</button> </form> ); } }
ReactDOM.render(<Login />, document.getElementById("test"));
|
高阶函数
高阶函数:如果一个函数符合下面 2 个规范中的任何一个,那该函数就是高阶函数。
- 若 A 函数,接收的参数是一个函数,那么 A 就可以称之为高阶函数。
- 若 A 函数,调用的返回值依然是一个函数,那么 A 就可以称之为高阶函数。
常见的高阶函数有:Promise
、setTimeout
、arr.map()
等等
函数柯里化
函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。 (注意对统一处理的理解)
1 2 3 4 5 6 7
| function sum(a) { return (b) => { return (c) => { return a + b + c; }; }; }
|
不用函数柯里化的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <script type="text/babel"> class Login extends React.Component{ state = { username:'', password:'' }
saveFormData = (dataType,event)=>{ this.setState({[dataType]:event.target.value}) }
handleSubmit = (event)=>{ event.preventDefault() const {username,password} = this.state alert(`你输入的用户名是:${username},你输入的密码是:${password}`) } render(){ return( <form onSubmit={this.handleSubmit}> 用户名:<input onChange={event => this.saveFormData('username',event) } type="text" name="username"/> 密码:<input onChange={event => this.saveFormData('password',event) } type="password" name="password"/> <button>登录</button> </form> ) } } ReactDOM.render(<Login/>,document.getElementById('test')) </script>
|