# 组件介绍
组件表示页面中的部分功能
组合多个组件实现完整的页面功能
可复用,独立(相互之间互不影响),可组合
# 组件的创建方式

## 使用函数创建组件
函数名称必须以大写字母开头
必须有返回值,返回组件结构
如果返回null表示不渲染任何内容

渲染组件:使用函数名作为组件标签名
```html
// function Hello(){
//   return (<div>展示的返回函数组件</div>)
// }
const Hello =()=><div>展示的返回函数组件</div>
ReactDOM.render(<Hello />,document.getElementById('root'))
```
## 使用类创建组件
类名称必须以大写字母开头
类组件必须继承React.Component父类
必须提供render方法
render方法必须有返回值.
```html
class HelloClass extends React.Component{
  render(){
    return (<div>leizujian</div>)
  }
}
ReactDOM.render(<HelloClass />,document.getElementById('root'))
```
## 抽离到独立的js文件
1. 创建HelloRender.js文件
2. 在HelloRender.js文件中导入React
3. 创建组件
4. 在HelloRender.js中导出该组件
5. 在index.js中导入HelloRender组件
6. 渲染组件
```html
import HelloRender from './learn/HelloRender'
ReactDOM.render(<HelloRender />,document.getElementById('root'))
```
```
import React from "react"

class HelloRender extends React.Component{
    render(){
        return (
            <div>抽离到js文件中的组件</div>
        )
    }
}

export default HelloRender
```

# 事件处理
驼峰命名
on+事件名称={事件处理程序}
## 类
```html
class AppOnClick extends React.Component{
  handleClick(){
    console.log('单机')
  }
  render(){
    return (
      <button onClick={this.handleClick}>点击</button>
    )
  }
}

ReactDOM.render(<AppOnClick />,document.getElementById('root'))
```
## 函数
```html
function AppOnClickFun(){
  function handleClick(){
    console.log('单机function')
  }
  return (
    <button onClick={handleClick}>点击</button>
  )
}
ReactDOM.render(<AppOnClickFun />,document.getElementById('root'))
```
## 事件对象
```html
class AppOnClickUrl extends React.Component{
  handleClick(e){
    // 阻止浏览器默认跳转行为
    e.preventDefault()
    console.log('单机,阻止浏览器默认跳转行为')
  }
  render(){
    return (
      <a href="http://www.baidu.com" onClick={this.handleClick}>点击</a>
    )
  }
}

ReactDOM.render(<AppOnClickUrl />,document.getElementById('root'))
```

## 有状态组件和无状态组件
状态(state)即数据
函数组件又叫无状态组件,只负责数据展示(静)
类组件又叫有状态组件,负责更新UI,让页面动起来



## 组件中的state和setState
```html
class AppState extends React.Component{
  constructor(){
    super()
    this.state= {
      count:0
    }
  }
  // state= {
  //   count:0
  // }
  render(){
    return (
      <div>有状态组件,{this.state.count}</div>
    )
  }
}

ReactDOM.render(<AppState />,document.getElementById('root'))
```
修改状态
```html
class AppState extends React.Component{
  constructor(){
    super()
    this.state= { 
      count:0,
      test:'a'
    }
  }
  // state= {
  //   count:0
  // }
  render(){
    return (
      <div>有状态组件,{this.state.count},{this.state.test}
      <button onClick={()=>{
        this.setState({
          count:this.state.count+1
        })
      }}>+1</button>
      </div>
    )
  }
}

ReactDOM.render(<AppState />,document.getElementById('root'))
```
事件处理程序中this的值为undefined,希望this指向组件实例
事件绑定this指向
1. 箭头函数,利用箭头函数自身不绑定this的特点.
```html
class AppStateJTThis extends React.Component{
  constructor(){
    super()
    this.state= {
      count:0
    }
  }
  onIncrement(){
    console.info('事件处理this'+this)
    this.setState({
      count:this.state.count+1
    })
  }
  render(){
    return (
      <div>有状态组件,{this.state.count}
      <button onClick={()=>this.onIncrement()}>+1</button>
      </div>
    )
  }
}

ReactDOM.render(<AppStateJTThis />,document.getElementById('root'))
```
2. Function.prototype.bind()利用ESS中bind方法,将时间处理程序中的this与组件实例绑定到一起
```html
class AppStateJTThis extends React.Component{
  constructor(){
    super()
    this.onIncrement= this.onIncrement.bind(this)
    this.state= {
      count:0
    }
  }
  onIncrement(){
    console.info('事件处理this'+this)
    this.setState({
      count:this.state.count+1
    })
  }
  render(){
    return (
      <div>有状态组件,{this.state.count}
      <button onClick={this.onIncrement}>+1</button>
      </div>
    )
  }
}

ReactDOM.render(<AppStateJTThis />,document.getElementById('root'))
```
3. class实例方法
```html
class AppStateJTThis extends React.Component{
  constructor(){
    super()
    this.state= {
      count:0
    }
  }
  onIncrement=()=>{
    console.info('事件处理this'+this)
    this.setState({
      count:this.state.count+1
    })
  }
  render(){
    return (
      <div>有状态组件,{this.state.count}
      <button onClick={this.onIncrement}>+1</button>
      </div>
    )
  }
}

ReactDOM.render(<AppStateJTThis />,document.getElementById('root'))
```
方法是一个特殊的属性.
类中的方法默认开启了局部严格模式,所以changeWeather中的this为undefined,
use strict  使用严格模式

实例调用,直接调用(严格模式下,this为undefined)

组件内的标签可以定义ref属性来标识自己

箭头函数中的this找外层的this.

## 事件处理
1. 通过onXxx属性指定事件处理函数,必须驼峰
    1. React使用的是自定义合成事件,而不是使用原生DOM事件,为了更好兼容性
    2. React中的事件是通过事件委托方式处理的(委托给组件最外层的元素),为了更高效
2. 可以通过event.target得到发生事件的DOM元素对象,避免过度使用ref


# 表单处理
## 受控组件,其值受到React控制的表单元素
1. html中表单元素是可输入的,也就是有自己的可变状态
2. react中可变状态通常通过state处理,并且只能通过setState()来处理
3. react将state与表单元素值value绑定到一起,由state的值来控制表单元素的值
4. 类似vue中双向绑定
### 使用步骤
1. 在state中添加一个状态,作为表单元素的value值(控制表单元素的来源)
2. 给表单元素绑定change事件,将表单元素的值设置为state值(控制表单元素值的变化)
### 使用一个事件处理程序同时处理多个表单元素
1. 给表单添加一个name属性,名称与state相同
2. 根据表单元素类型获取对应值 
3. 在change事件处理程序中通过name来修改对应的state
```html
class AppInput extends React.Component{
  constructor(){
    super()
    this.state= {
      txt:'请输入值',
      context:'',
      city:'bj',
      isChecked:false
    }
  }
  handleClick=e=>{
    console.info('事件处理this'+this)
    const target = e.target;
    const value = target.type === 'checkbox'?target.checked:target.value
    const name = target.name
    this.setState({
      [name]: value
    })
    console.info('name:'+name+',value:'+value)
  }
  render(){
    return (
      <div><input type='text' name='txt' value = {this.state.txt} onChange={this.handleClick}/>
      <br/>
      <textarea value={this.state.context} name= 'context' onChange={this.handleClick}/>
      <br/>
      <select value={this.state.city}  onChange={this.handleClick} name = 'city'>
      <option value="bj">北京</option>
        <option value="sh">上海</option>
        <option value="gz">广州</option>
      </select>
      <input type='checkbox' name='isChecked' checked = {this.state.isChecked} onChange={this.handleClick}/>

      </div>
    )
  }
}

ReactDOM.render(<AppInput />,document.getElementById('root'))
```
### 高阶函数
如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数.
1. 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数
2. 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数
函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式.
## 非受控组件
借助于ref,使用原生DOM方式来获取表单元素值
ref作用:获取DOM或组件
```html
class APPRef extends React.Component{
  constructor(){
    super()
    // 创建ref对象
    this.txtRef = React.createRef()
  }
  getTxt=()=>{
    console.log('文本框值为',this.txtRef.current.value)
  }
  render(){
    return(
      <div>
        <input type="text"ref = {this.txtRef}/>
        <button onClick= {this.getTxt}>获取文本信息</button>
      </div>
    )
  }
}

ReactDOM.render(<APPRef />,document.getElementById('root'))
```
