react
尚硅谷react教程
-
jsx语法规则
1.定义虚拟dom时不加引号(不是字符串)
2.标签中混入js表达式时要用{}
js表达式与js语句不同。
js语句是if(),for(),switch()等等。
const data = ['a','b','c']; const VDOM=( <div> <ul> { data.map((item)=>{ return <li>{item}</li> }) } </ul> </div> )
3.样式的类名要用className
className='title'
4.内联样式
style={{color:'white'}}
5.只有一个根标签
6.标签必须闭合
<button></button> <button/>
7.标签首字母
小写字母开头 将标签转为html;若无则报错
大写字母开头 渲染相应组件,若组件无定义报错
-
constructor()构造器
构造器不传props会出现未知错误
是否传递取决于是否希望在构造器中使用this.props
class MyComponent extends React.Component{ constructor(props){ super(props)//必传 this.state={ihHot:true} } }
constructor一般可以不写,写的时候用于以下俩种情况:
1.初始化内部state (this.state)
2.为时间处理函数绑定实例(this指向问题)
-
函数式组件
函数定义首字母大写,渲染页面时函数写成闭合标签
-
类式组件
1.类中的构造器不是必须写。需要对示例初始化(添加属性)的时候写
2.如果A继承B类,且A类中写了构造器,则A类构造器中super必须调用
3.类中所定义的方法都放在类的原型对象上,供实例使用
4.类中可以直接写赋值语句
class MyComponent extends React.Component{ render(){ return } }
-
类式组件实例三大核心属性
-
1.state:改变组件状态
1)基本使用
class MyComponent extends React.Component{ constructor(props){ super(props) this.state={isHot:true} } }
class MyComponent extends React.Component{ state={}//初始化状态 }
2)状态使用setState()合并更改,不是替换
每次setState都会重新调用render
this.setState({isHot:!isHot})
3)constructor和render中this都指向组件。
组件自定义方法this指向undefined,通过以下俩种方法指向组件
changeweather=()=> {//this指向父层 }
class MyComponent extends React.Component{ constructor(props){ super(props) this.state={ihHot:true} this.changeweather=this.demo.bind(this) //右侧的this.demo即下面的demo方法,bind生成新函数,实例对象变为括号里的this } render(){ const {isHot}=this.state return <h2 onClick={this.changeweather}>今天天气{isHot?'炎热':'凉爽'}</h2> } demo() { const isHot=this.state.isHot; this.setState({isHot:!isHot}) } }
-
2.props:给组件传入数据
-
花括号代表里面是js代码,… 是展开运算符
展开运算符一般用于展开数组,拼接数组
const arr1=[1,2,3]; const arr2=[4,5,6]; const arr3=[...arr1,...arr2]
只有这种时候可以使用…p展开运算符展开遍历对象
class Person extends React.Component{ render(){ const {name,age,sex}=this.props return ( <ul> <li>姓名{name}</li> <li>sex{sex}</li> <li>age{age}</li> </ul> ) } } const p={name:"xw",age:17,sex:'nv'} ReactDOM.render(<Person {...p}/>,document.querySelector('.demo'))
-
Prop是只读的
对props实例限制,大小写敏感
Person.propTypes={ name:PropTypes.string.isRequired,//name只能是string类型且实例时必须传入 sex:PropTypes.string, age:PropTypes.number, speak:PropTypes.func, }
对props默认值
Person.defaultProps={ sex:'没有传性别', age:18 }
-
Prop简写
class Person extends React.Component{ static propTypes={ name:PropTypes.string.isRequired, sex:PropTypes.string, age:PropTypes.number, speak:PropTypes.func, } static defaultProps={ sex:'没有传性别', age:18 } render(){ const {name,age,sex}=this.props return ( <ul> <li>姓名{name}</li> <li>sex{sex}</li> <li>age{age}</li> </ul> ) } }
-
函数式组件使用props
function Person(props) { const {name,age,sex}=props return ( <ul> <li>姓名:{name}</li> <li>{sex}</li> <li>{age}</li> </ul> ) } Person.propTypes={//限制 } Person.defaultProps={//默认参数 } ReactDOM.render(<Person name="qq" age={18} sex="女" />,document.querySelector('.text'))
-
-
3.refs:绑定俩个组件
-
字符串形式的ref(不推荐使用)
class Demo extends React.Component{ showData=()=>{ const {button1}=this.refs alert(button1.value) } render(){ return( <div> <input ref="button1" type="text"/> <button onClick={this.showData}>点我</button> </div> ) } } ReactDOM.render(<Demo/>,document.querySelector(".text"));
-
ref回调函数
ref回调函数如果以内联函数的方式定义,在节点更新过程中重新执行render,ref回调函数被执行俩次,第一次传入参数null(清空ref),第二次传入dom节点,定义成类的绑定函数可以避免更新时调用俩次的问题(不会清空ref)
class Demo extends React.Component{ showData=()=>{ const {button1}=this alert(button1.value) } render(){ return( <div> <input ref={(a)=>{this.button1=a}} type="text"/> <button onClick={this.showData}>点我</button> </div> ) } } ReactDOM.render(<Demo/>,document.querySelector(".demo"));
简写
<input ref={c=>this.input1=c} type="text"/>
定义成类的绑定函数
<input ref={this.saveInput} type="text"/>
-
React.creatRef(推荐)
可以返回一个容器,该容器可以存储被ref所标识的一个节点(不能是多个)
class Demo extends React.Component{ myRef=React.createRef()//创建ref showData=()=>{ console.log(this.myRef.current.value); } render(){ return( <div> <input ref={this.myRef} type="text"/> <button onClick={this.showData}>点我</button> </div> ) } }
-
event.target
避免过度使用ref:如果操作的dom和触发事件的dom为同一个则可以通过event.target
showData=(event)=>{ alert(event.target.value)//拿到input的值 } render(){ return( <input onBlur={this.showData} type="text"/>//失去焦点触发showData ) }
-
-
-
受控组件和非受控组件
输入类dom现用现取即为非受控组件
受控组件如下代码(随着输入已经存储入state,使用时再从state中取出)
demo = (event)=>{ console.log(event.target.value) } <input onChange={this.demo} type="text"/>
-
高阶函数
高阶函数分为俩种:1.接收的参数是函数 2.返回值是函数
常见高阶函数:Promise,setTimeout,arr.map()
new Promise(()=>{}) setTimeout(()=>{})
函数的柯里化:通过函数调用返回函数,实现多次接收参数最后统一处理的函数编码形式
-
柯里化 返回值函数实例
onChange调用的是saveForm函数
<input onChange={this.saveForm} type="text" name="username"/>
实例:onChange调用return返回值
saveForm=(dataType)=>{ return (event)=>{ this.setState({[dataType]:event.target.value}) } } <input onChange={this.saveForm('username')} type="text" name="username"/>
-
不用柯里化的实现方式
saveFormData=(dataType,event)=>{ this.setState({[dataType]:event.target.value}) } 用户名<input onChange={(event)=>{this.saveFormData('username',event)} type="text" name="username"}> 密码<input onChange={event => this.saveFormData('password',event) type="password" name="password"}>
-
-
生命周期回调函数
生命周期钩子函数,生命周期函数,生命周期钩子
-
旧版
初始化阶段 constructor()//构造器 componentWillMount()//组件将要挂载 render() componentDidMount(){}//组件挂载完毕(一般做初始化:开启定时器,发起网络请求,订阅信息) 更新阶段:由this.setState或父组件重新更新render触发 shouldComponentUpdate()//询问它是否允许更新组件(默认返回值是true) render(){}//初始化渲染,状态更新以后 卸载组件 componentWillUnmount(){}//组件将要卸载时(一般做收尾:清理定时器等)
生命周期流程图:forceUpdate()不更改状态中的数据强制更新
-
新版
新版本(即将过时,避免使用) UNSAFE_componentWillReceiveProps() UNSAFE_componentWillMount() UNSAFE_componentWillUpdate()
getDerivedStateFromProps(){}//可以返回null或状态对象 getDerivedStateFromProps(props,state){return props}//返回state obj后无法修改该obj
getSnapshotBeforeUpdate(preprops,prestate){return props,state} componentDidUpdate(snapshotValue){}//接收到快照返回值
-
-
key的一些问题
虚拟DOM中key用于数据更新,React会将新虚拟DOM与旧虚拟DOM的diff比较
-
用map中的index作为key可能引发的问题
1、若对数据进行:逆序添加,逆序删除等破环顺序的操作
会产生没有必要的真实DOM更新,效率低
2、如果包含输入类DOM(类似于input)
会产生错误DOM更新:界面有问题
-
-
Todolist的总结
-
连续解构赋值+重命名
-
解决多级路径刷新页面样式丢失的问题