1、项目搭建与结构
2、类组件和函数组件
主要区别:1、函数组件没有生命周期2、函数组件没有this指向3、函数组件没有状态4、函数组件通过hooks实现各种操作5、props在函数的第一个参数接收6、函数体相当于类组件的render函数
import React from 'react'function App() {function Fn() {return <div>fn hello</div>}class ClassHello extends React.Component{constructor(props) {super(props)}render() {return <div>class hello</div>}}return (<div className="App"><Fn></Fn><ClassHello></ClassHello></div>);
}export default App;
3、js与jsx语法
1、jsx和react是相互独立的2、写法相似,更加简便3、可以和js混用4、最终会转化为和一个【React-element对象】5、不借助jsx,可以通过React.createElement创建
3.1 创建DOM的两种方式
二者最终得到的内容是一致的,均是React的element对象
import React from 'react'function App() {function Fn() {return React.createElement('div',[],'hello,fn')}class ClassHe extends React.Component{constructor(props) {super(props)}render() {return <div>hello,class</div>}}return (<div className="App"><Fn></Fn><ClassHe></ClassHe></div>);
}export default App;
3.2 jsx中不同类型数据的渲染.js
1、字符串/数字 => 直接渲染2、对象(vue中当成字符串渲染)element对象 => 直接渲染 普通对象 => 取到每一项后可以渲染3、数组(普通/元素数组) => 把数组中的每一项进行渲染4、表达式 => 得到运行结果渲染5、方法 => 无法渲染6、布尔值 => 不渲染7、undefined/null => 不渲染
import React from 'react'function App() {const str = 'good !!!'const num = 123const obj = {a:1}const eleObj = <span>span</span>const arr = [1, 2, 3]const eleArr = [<p>1111</p>,<p>2222</p>,<p>3333</p>]const boll = falsevar ss const na = nullreturn (<div className="App"><span> 字符串:</span> {str} <br /><span> 数字:</span>{num} <br /><span>普通对象:</span>{}{obj.a} <br /><span>元素对象:</span>{eleObj} <br /><span>普通数组:</span>{arr} <br /><span>元素数组:</span>{eleArr}<span>表达式:</span>{arr.length === 3 ? obj.a : ''} <br /><span>布尔值:</span>{boll} <br /><span>undefined:</span>{ss} <br /><span>null:</span>{na} <br /></div>);
}export default App;
4、事件绑定
1、写法类似原生 on + 方法名(首字母大写)2、给事件赋值为某个方法,但是不要执行
4.1 方法写在外面
import React from 'react'class App extends React.Component{
handleClick = ()=> {console.log('点击了按钮');
}
render() {return (<button onClick={this.handleClick}>点我触发事件</button>)
}
}export default App;
4.2 方法写在里面
import React from 'react'class App extends React.Component{render() {return (<button onClick={() => {console.log('点击了按钮');}}>点我触发事件</button>)}
}export default App;
4.3 注意事项
【特别注意】1、类组件想要拿到事件处理函数中this要处理 不然会undefined(1) 事件处理函数声明时,声明为【箭头函数+赋值语句】(2) 使用bind改变this指向,在需要传参时多用(3) 内联式写法,函数写为【匿名函数+箭头函数】2、给事件绑定的是一个方法,且不要直接调用
- 事件处理函数声明时,声明为【箭头函数+赋值语句】
import React from 'react'class App extends React.Component{
handleClick = ()=> {console.log(this);
}
render() {return (<button onClick={this.handleClick()}>点我触发事件</button>)
}
}export default App;
- 使用bind改变this指向,在需要传参时多用
import React from 'react'class App extends React.Component{handleClick(a){console.log(this,a); }render() {return (<button onClick={this.handleClick.bind(this,'传参')}>点我触发事件</button>)}
}export default App;
- 内联式写法,函数写为【匿名函数+箭头函数】
import React from 'react'class App extends React.Component{render() {return (<button onClick={() => {console.log(this); }}>点我触发事件</button>)}
}export default App;
4.4 事件绑定其他操作
1、传递参数 :bind(this,'参数')2、获取事件对象 e3、阻止默认行为、冒泡等
import React from 'react'class App extends React.Component {handleClick = (a,b,e) => {console.log('接收参数', a, b); console.log('合成事件对象', e);console.log('原生事件对象', e.nativeEvent);e.stopPropagation(); e.preventDefault(); }render() {return (<button onClick={this.handleClick.bind(this,1,2)}>点我触发事件</button>)}
}
export default App;
5、响应式数据(类组件)
1、react不能像vue一样【直接修改】触发更新2、react直接修改能修改值,无法触发更新3、react没有像vue的get和set监听,借助【setState】触发更新
5.1 setState的本质
1、修改数据2、触发更新
以下两种写法是等价的add = () => {this.setState({a:++this.state.a})}add = () => {this.state.a += 1this.setState({})}
5.2 setState 获取最新值
1、setState 修改值是异步操作2、获取最新值要在setStete第二个参数【回调函数】中获取
this.setState({a:++this.state.a}, () => {console.log('拿到a最新的值',this.state.a);})
5.3 setState 细节
1、setState传递对象,通过浅合并(Object.assign),并非替换2、由于浅合并,深层次的修改需要先赋值一份
import React from 'react'class App extends React.Component {state = {a: 0,b: 1,c: {c1: 2,c2: 3}}add = () => {this.setState({a: ++this.state.a,c: {...this.state.c,c2:4}}, () => {console.log('拿到a最新的值',this.state.a);})}render() {return <div><span>获取状态:</span>{this.state.a} <br /><span>c2的值:</span>{this.state.c.c2} <br /><span>修改状态:</span><button onClick={this.add}>点我修改</button> <br /></div>}
}export default App;
5.4 setState的一些特性
1、多次修改数据,会合并为一次,最后触发更新2、setState每次调用都会触发更新(无论数据是否修改)借助 PureComponent 优化类组件a、数据不变,组件不刷新b、当修改对象和数组时,要先解除引用,否则不更新3、不要再render中调用setState
addArr1 = () => {this.state.arr.push(4)this.setState({arr:this.state.arr}, () => {console.log(this.state.arr);})}addArr = () => {let arr_ = [...this.state.arr]arr_.push(4)this.setState({arr: arr_}, () => {console.log(this.state.arr);})}
6、条件渲染
1、利用js编写自定义逻辑2、根据逻辑(true/false)渲染相应的内容3、主要方式(1) 三元表达式(2) && ||(3) if else
import React from 'react'class App extends React.PureComponent {state = {show: true,isHot:true}fn = () => {if (this.state.show) {return <span>if</span>} else {return <span>else</span>}}handleClick = () => {this.setState({show: !this.state.show,isHot:!this.state.isHot})}render() {return <div><h3>条件渲染</h3>{}{this.state.show ? '显示' : '隐藏'} <br />{}{this.state.isHot && '天气很热'} <br />{}{this.fn()} <br /><button onClick={this.handleClick}>点我切换</button></div>}
}export default App;
7、列表渲染
1、使用数组遍历方法 将后端返回的数组中每一项取出来渲染成jsx(1) 拿到原始数据:后端数据(2) 将每一项数据转化为DOM元素(3) jsx 渲染2、常用方法(1) map 有返回值(2) forEach 没有返回值(3) filter 过滤
import React from 'react'class App extends React.PureComponent {state = {arr: [1, 2, 3],eleArr: [<div>1</div>,<div>2</div>,<div>3</div>,]}getArr = () => {let newArr = []this.state.arr.forEach(item => {newArr.push(<p key={item}>{ item}</p>)})return newArr}render() {return <div><h3>列表渲染</h3>{this.state.arr} <br />{this.state.eleArr}<hr />{}{this.state.arr.map(item => (<h3 key={item}>{ item }</h3>))}<hr />{}{this.getArr()}</div>}
}export default App;
8、样式操作
1、class类名设置(1) 必须写成 className(2) 样式单独写在一个css文件中如果不做处理,样式会全局生效(产生样式污染)(3) 只能接受一个字符串 '' {}2、style内联写法不能像原生一样写成字符串'',必须写成对象 {{ }}3、解决样式污染(1) 改名 将 .css => .module.css(2) 将样式文件引入为对象 import sonStyle from ''(3)【sonStyle.son】/【sonStyle['son']】取出类名使用4、动态控制类名引入状态,根据状态使用条件渲染出切换类名(拼接字符串)(1) 手动拼接字符串(少量)(2) 借助 classnames 拼接a、帮助我们生成计算好的类名的字符串
8.1 手动拼接字符串
import React from 'react'
import './App.css'class App extends React.PureComponent {state = {isShow : true}handle = () => {this.setState({isShow:!this.state.isShow})}render() {return (<div className="App">{}<span className={ this.state.isShow ? 'color' :''}> 动态添加类名</span> <br /><button onClick={this.handle}>点我切换</button></div>)}
}export default App;
8.2 借助 classnames 拼接
import React from 'react'
import classnames from'classnames'
import style from'./App.module.css'class App extends React.PureComponent {state = {isShow : true}handle = () => {this.setState({isShow:!this.state.isShow})}render() {return (<div className={style.App}>{}<span className={classnames({{}[style['color']]:this.state.isShow})}> 动态添加类名</span> <br /><button onClick={this.handle}>点我切换</button></div>)}
}export default App;
9、受控组件和非受控组件
回想原生:1、获取表单的值 onInput={this.handleClick}a、绑定监听事件 input/changeb、通过【e.target.value】获取2、设置表单的值 value={this.state.inputValue}设置value/checke属性
import React from 'react'class App extends React.PureComponent {state = {inputValue:''}handleClick = (e) => {this.setState({inputValue: e.target.value})}change = () => {this.setState({inputValue: 11})}render() {return (<div><input value={this.state.inputValue} onInput={this.handleClick} /><span> {this.state.inputValue}</span> <br /><button onClick={this.change}>变更inputValue</button></div>)}
}export default App;
9.1 受控组件(双向的)
1、表单的值可以获取【state】,并可以由开发者靠代码【setState】去更改2、可以通过设置state中的值改变表单中的值3、将表单数据添加到state中,可以通过【state/setState】对数据进行获取和修改
9.2 受控组件(无状态的)
1、表单的值我们只能获取【通过给输入框打标识获取】2、我们仅做了事件监听,没有设置 value/checked 属性3、没有设置 state
9.3 关于复选框
1、 value 选中后的值2、checked 控制是否选中