目录
一、React表单与事件
1、React表单组件
(1)受控组件与非受控组件——笔试题
(2)更多受控组件
2、React事件
(1)事件类型
(2)事件对象
(3)事件绑定——this为unde
二、React组件生命周期
1、组件的生命周期
2、生命周期钩子详解
- **componentWillMount** :
- **componentDidMount** :
- **componentWillReceiveProps** :
- **shouldComponentUpdate** :
- **componentWillUpdate**:
render函数 在这中间执行
- **componentDidUpdate** :
- **componentWillUnmount**:
3、生命周期钩子——网络请求
在HTML中,表单元素与其他元素最大的不同是它自带值或数据
而且,只要是有表单出现的地方,就会有用户输入,表单事件触发,就会涉及的数据处理。
在我们用React开发应用时,为了更好地管理应用中的数据,响应用户的输入,编写组件的时候呢,我们就会运用到**受控组件与非受控组件**这两个概念。
React推荐我们在绝大多数情况下都使用受控组件。这样可以保证表单的数据在组件的state管理之下,而不是各自独立保有各自的数据。
没有v-model,需要自己去实现
**受控组件**简单来说就是它的值由React进行管理,
而**非受控组件**的值则由原生DOM进行管理。
- 受控组件:==>双向
一般涉及到表单元素时我们才会使用这种分类方法。
受控组件的值由props或state传入给受控组件(表单的输入框),用户在元素上交互或输入内容会引起应用state的改变。
在state改变之后重新渲染组件,我们才能在页面中看到元素中值的变化,
假如组件没有绑定事件处理函数改变state,用户的输入是不会起到任何效果的,这也就是“受控”的含义所在。
- 非受控组件:==>单向
类似于传统的DOM表单控件,用户输入不会直接引起应用state的变化,我们也不会直接为非受控组件传入值。
想要获取非受控组件,我们需要使用一个特殊的ref属性,同样也可以使用defaultValue属性来为其指定一次性的默认值。
示例如下:
import React from "react" class App extends React.Component { constructor(arg) { super(arg) this.state = {} this.handleChange = (e) => { this.setState({ value: e.target.value }); // e.target.value就是输入的值 } } render() { return ( <div> {/* 1、受控组件 */} <input type='text' value={this.state.value} onChange={this.handleChange} /> {/* 2、非受控组件 */} <input type="text" value={this.state.value} /> {/* 如果上没有onChange事件,输入框不能输入,value会一直是this.state.value */} <input type="text" defaultValue="hello!" /> </div> ) } } export default App
在组件中声明表单元素(input_type/checked textarea select ……)时,一般都要为表单元素传入应用状态中的值,我们需要根据表单元素中用户的输入,对应用数据进行相应的操作和改变。
1、radio:
class MyApp extends React.Component { constructor(props) { super(props); this.state = { gender: '' }; this.handleGender = this.handleGender.bind(this); } handleGender(event) { this.setState({gender: event.target.value}); } render() { return ( <div> <h2>input_checked 受控组件</h2> <input type='radio' value="man" checked={this.state.gender=='man'} onChange={this.handleGender}/>男<br /> <input type='radio' value="woman" checked={this.state.gender=='woman'} onChange={this.handleGender}/>女<br /> <div>{this.state.gender}</div> </div> ); } } ReactDOM.render( <MyApp />, document.getElementById('root') );
2、mycheck:
import React, { Component } from 'react' export default class Mycheck extends Component { constructor(){ super() this.state={ chengdu:true } this.chengduchange=(e)=>{ console.log(e.target.checked) this.state.chengdu=e.target.checked this.setState(this.state) } } render() { return ( <div> <input type="checkbox" name='city' value="chengdu" checked={this.state.chengdu} onChange={this.chengduchange}/> <input type="checkbox" name='city' value="shanghai"/> <input type="checkbox" name='city' value="beijing"/> <input type="checkbox" name='city' value="tianjing"/> </div> ) } }
3、mydata
import React, { Component } from 'react' export default class Mydate extends Component { constructor(){ super() this.state={ v:"2021-11-11" } this.change1=(e)=>{ console.log(e.target.value) this.state.v=e.target.value this.setState(this.state) } } render() { return ( <div> <input type="date" value={this.state.v} onChange={this.change1}/> </div> ) } }
4、myfile
import React, { Component } from 'react' export default class Myfile extends Component { constructor(){ super() this.state={ v:"" } this.change1=(e)=>{ console.log(e.target.files[0]) this.state.v=e.target.files[0] this.setState(this.state) } } render() { return ( <div> <input type="file" onChange={this.change1}/> </div> ) } }
5、myselect
import React, { Component } from 'react' export default class Myselect extends Component { constructor(){ super() this.state={ v:"beijing" } this.change1=(e)=>{ console.log(e.target.value) this.state.v=e.target.value this.setState(this.state) } this.send=()=>{ console.log(this.state.v) } } render() { return ( <div> <select name="city" value={this.state.v} onChange={this.change1}> <option value="chengdu">成都</option> <option value="beijing">北京</option> <option value="shanghai">上海</option> </select> <button onClick={this.send}>发送</button> </div> ) } }
7、mytext
import React, { Component } from 'react' export default class Mytext extends Component { constructor(arg){ super(arg) this.state={msg:"66666"} this.input1=(e)=>{ console.log(e.target.value) this.state.msg=e.target.value this.setState(this.state) } } render() { return ( <div> <p>{this.state.msg}</p> <input type="text" value={this.state.msg} onInput={this.input1} /> <input type="text" /> </div> ) } }
使用React元素处理事件与处理DOM元素上的事件非常相似。不过有一些语法上的差异:
- React事件使用**小驼峰命名法**,而不是全部小写命名。
- React事件使用JSX传递一个函数作为事件处理程序,而不是一个字符串。示例:
- 鼠标事件:onClick onDoubleClick onMouseDown
- 触摸事件:onTouchStart onTouchMove onTouchEnd
- 键盘事件:onKeyDown
- 剪切事件:onCopy onCut onPaste
- 表单事件:onChange onInput onSubmit
- 焦点事件:onFocus
- UI事件:onScroll
- 滚动事件:onWheel
构造函数:fun
- React对原生的事件系统也进行了封装,在React中的事件对象实际上是一个跨浏览器的**虚拟事件对象** ,它拥有和原生事件对象相同的属性和方法。
- 在react 中使用“return false” 无法阻止默认事件,只能通过事件对象调用“event.preventDefault() ”进行阻止
class ClickEvent extends React.Component { constructor(props) { super(props); this.state = { value: 'hello world' }; //函数写法==> 方法1: this.changeData = this.changeData.bind(this); //方法2: this.fm=()=>{} } //方法3: changeData(event) { //changeData函数也可以写在构造函数constructor内,写this.changeData都能调用到这个给函数 console.log(event) this.setState({value: '萨瓦迪卡'}); } fn(arg){} //方法4: fn1=function(){} //方法5: fn2=()=>{} render() { return ( <div> <button onClick={this.changeData}>点击改变</button> <h2>{this.state.value}</h2> //方法6:因为react中函数不能写小括号,所以自己设计,去实现有小括号,传参 <button onClick={(e)=>{this.fn(100)}}>函数传参</button> </div> ); } }
事件处理函数内部使用this 关键词时其指向==>
class ClickEvent extends React.Component { constructor(arg) { super(arg) this.changeData=function (){console.log(this);} //undefined } changeData() { console.log(this);//undefined } render() { return ( <div> <button onClick={this.changeData}>点击改变</button> </div> ); } }
解决方法:
1、将函数写在constructor 内部,对事件处理函数bind 绑定this(官方推荐)
2、 每次事件绑定都对事件处理函数做bind 绑定
3、定义事件处理函数时使用箭头函数
<button onClick={e=>this.changeData.call(this)}>点击改变</button>
当事件处理函数需要传参时:
<button onClick={this.changeData.bind(this,id)}>点击改变</button> //将changeData处理为有this <h2>{e=>this.changeData.call(id,event)}</h2> //又想传参又要处理this,就用call
import React, { Component } from 'react' export default class App extends Component { constructor() { super() this.fn = () => { console.log(1111, this.state) } this.fn3 = function () { console.log(333, this.state) }.bind(this) // this.state={} } fn2() { console.log(2222, this.state) } fn4 = function () { console.log(44444, this) } fn5 = () => { console.log(555, this) } fn6(arg) { console.log(arg) } fn7(id) { console.log(id) } state = { msg: "hello", arr: [{ id: 123, title: "a" }, { id: 124, title: "bb" }] } render() { return ( <div> <button onClick={this.fn}>btn</button> <button onClick={this.fn2.bind(this)}>btn2</button> <button onClick={this.fn3}>btn3</button> <button onClick={this.fn4.bind(this)}>btn4</button> {/* <button onClick={(e)=>{this.fn4(this,e)}}>btn4</button> */} <p>{this.state.msg}</p> <button onClick={this.fn5}>btn5</button> <button onClick={(e) => { this.fn6(100) }}>btn6</button> { this.state.arr.map(el => (<div key={el.id}> <p>{el.title}</p> <button onClick={(e) => { this.fn7(el.id) }}>btn</button> </div>)) } </div> ) } }
render函数 在页面初次加载的时候,会运行;数据每改变一次,页面刷新的时候也会运行。
构造函数只会调用一次,从创建到销毁都只调用一次。
- Mounting:已插入真实 DOM
- Updating:正在被重新渲染
- Unmounting:已移出真实 DOM
组件创建阶段(初始加载):一辈子只执行一次 构造函数(有争议,因为构造函数不算生命周期函数)、componentWillMount: render: componentDidMount:
组件运行阶段:按需,根据props 属性或state 状态的改变,有选择性的执行0 到多次 componentWillReceiveProps: shouldComponentUpdate: componentWillUpdate: render: componentDidUpdate:
组件销毁阶段:一辈子只执行一次
因为没有了创建前后,想做预加载,就在构造函数或者componentWillMount中做
定义:在特定的阶段,你刚刚自动执行的函数(方法)
- **componentWillMount** :
在渲染前调用,在客户端也在服务端。
- **componentDidMount** :在**第一次渲染后**调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异部操作阻塞UI)。
- **componentWillReceiveProps** :在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
- **shouldComponentUpdate** :自己判断是否需要刷新
返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。 可以在你确认不需要更新组件时使用。
- **componentWillUpdate**:准备更新
在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
render函数 在这中间执行
- **componentDidUpdate** :已经更新,数据已经改完了
在组件完成更新后立即调用。在初始化时不会被调用。
- **componentWillUnmount**:即将销毁
在组件从 DOM 中移除的时候立刻被调用。
class MyApp extends React.Component { constructor(props) { super(props); this.state = { date: new Date() }; } //通过componentDidMount 方法设置一个定时器,每隔1秒重新设置时间,并重新渲染: componentDidMount() { var oThis=this; clearInterval(this.timer); this.timer=setInterval(function() { oThis.setState({ date: new Date() }) }, 1000) } render(){ return ( <h2>{this.state.date.toLocaleTimeString()}</h2> ); } }
父组件的状态传递到子组件的属性中
class Content extends React.Component { //在渲染前调用,在客户端也在服务端 componentWillMount() { console.log('Component WILL MOUNT!') } //在第一次渲染后调用,只在客户端 componentDidMount() { console.log('Component DID MOUNT!') } //在组件接收到一个新的 prop (更新后)时被调用 componentWillReceiveProps(newProps) { console.log('Component WILL RECEIVE PROPS!') } //在组件接收到新的props或者state时被调用 shouldComponentUpdate(newProps, newState) { return true; } //在组件接收到新的props或者state但还没有render时被调用 componentWillUpdate(nextProps, nextState) { console.log('Component WILL UPDATE!'); } //在组件完成更新后立即调用 componentDidUpdate(prevProps, prevState) { console.log('Component DID UPDATE!') } //在组件从 DOM 中移除的时候立刻被调用 componentWillUnmount() { console.log('Component WILL UNMOUNT!') } render() { return ( <div> <h3>{this.props.myNumber}</h3> </div> ); } } class MyApp extends React.Component { constructor(props) { super(props); //声明状态 this.state = { data: 0, isRender: true }; this.setNewNumber = this.setNewNumber.bind(this); this.deleteDOM = this.deleteDOM.bind(this); } //改变状态值并传递到子组件 setNewNumber() { this.setState({data: this.state.data + 1}); } //删除子组件 deleteDOM() { this.setState({isRender: false}) } render() { return ( <div> <button onClick={this.setNewNumber}>点我改变状态</button> <button onClick={this.deleteDOM}>点我删除子组件</button> { this.state.isRender ? <Content myNumber={this.state.data} /> : null } </div> ); } } ReactDOM.render( <div> <MyApp /> </div>, document.getElementById('root') );
import React, { Component } from 'react' export default class Box extends Component { constructor() { super() this.state = { count: 2, token: "abcdqwe" } this.increment1 = function () { this.setState({ count: this.state.count + 1 }) } this.changetoken = function () { this.setState({ token: "abcdqwe2" }) } console.log("constructor") } render() { console.log("render--box") return ( <div> <p>{this.state.count}</p> <button onClick={this.increment1.bind(this)}>count++</button> <button onClick={this.changetoken.bind(this)}>change_token</button> </div> ) } componentWillMount() { console.log("componentWillMount") } componentWillReceiveProps() { console.log("componentWillReceiveProps") } componentDidMount() { console.log("componentDidMount") } componentWillUpdate() { console.log("componentWillUpdate") } shouldComponentUpdate() { console.log("shouldComponentUpdate", arguments) //只有传入的有count而是是新值 才更新 if (arguments[1].count && arguments[1].count != this.state.count) { return true } else { return false } } componentDidUpdate() { console.log("componentDidUpdate") } componentWillUnmount() { console.log("componentWillUnmount") } }
componentDidMount
import React, { Component } from 'react' export default class Box2 extends Component { state={ arr:[] } render() { return ( <div> <h1>box2</h1> { this.state.arr.map(el=><div>{el.title}----{el.age}</div>) } </div> ) } componentDidMount(){ fetch("http://192.168.6.78:7001/test").then(res=>res.json()) .then(data=>{ console.log(data) this.state.arr=data this.setState(this.state) }) } }