一、初识React
React使用jsx来写,jsx是js的语法糖,实际还是用的js只是代码编写更简便
二、jsx语法规则
1、定义虚拟DOM不要加引号
2、标签内需要用到js表达式时,用{}(表达式是指会产生一个值的式子,map(),function(){}都是表达式),React中表达式为数组时会自动遍历里面元素,遍历数组用的比较多的是map
const data = ["angular", "vue", "react"] const vDom = <ul>前端框架有{ data.map((item, index) => { return <li key={index}>{item}</li> }) }</ul>
3、给标签指定类名用className而不是class
4、一个虚拟DOM表达式只能有一个根标签
5、标签必须闭合
6、内联样式,要用style={{样式名:'样式值'}},样式值为js表达式时不用再包{}
7、标签若首字母小写,则在转换时会直接在对应html里找同名标签,若找不到则报错
若首字母大写,则会去找对应的自定义组件,若没有则报错
8、事件绑定,事件名通过this拿到,且也需要{}包起来,js表达式都需要!!!
三、两种组件:函数式组件(用于简单)、类式组件(用于复杂)
(一)、函数式组件
即用一个函数来申明组件,注意函数名即组件名,必须首字母大写,且函数必须有返回值
var data = ["xixi", "huhu"] function Mycomponent() { return data.map((item, index) => { return <h1 key={index}>{item}</h1> }) }
渲染时,不能写函数名要写成标签形式。此处渲染①遇到标签名首字母大写,去找自定义组件;②发现是函数式组件,调用该函数
ReactDOM.render(<Mycomponent />, document.getElementById("test"))
(二)、类式组件
1、声明组件:
①必须继承React.Component。
②类不是必须写construster构造器,但必须要有render(){},
③render()存在于类的原型对象上,是给实例用的
④render()内部必须要有返回值
⑤子类必须在constructor中调用super()
var data = ["xixi", "huhu"] class MyComponent extends React.Component { render() { return data.map((item, index) => { return <h2 key={index}>{item}</h2> }) } }
渲染:也要写成标签形式,过程:①遇到首字母大写的虚拟DOM去找自定义组件;②发现是类式组件,去new 类生成实例化对象,且由实例化对象调用render()
ReactDOM.render(<MyComponent />, document.getElementById("test"))
2、constructor
①子类中必须调用super,且要在最前面,且要接并super传props
②一般用于初始化状态(state写在这里)和修改方法this指向
constructor(props) { super(props) this.state = { isHot: true,wind:false } // 解决办法:用bind手动设置changeWeather的this指向,且拷贝一份到当前实例对象身上(原型对象上本来有一份,但this为undefined) this.changeWeather = this.changeWeather.bind(this) }
3、render
内部return 标签等
①绑定事件要用驼峰:onClick
4、三大属性之一:state
state是类式组件实例化对象的三大属性之一,翻译为状态,里面一般存放数据,形式为对象
this.state = { isHot: true,wind:false }
注意!修改state需用API:setState
直接使用this.state.xx=值,不能真正修改state,使页面渲染改变,必须用API:setState
ps:修改是与原state合并,不是完全覆盖
changeWeather() { this.setState({ isHot: !isHot }) }
state简写
state可以直接采用赋值语句在类中constructor外,这样会直接绑定在实例对象身上
constructor(props) { super(props) } state = { isHot: true, wind: false }
5、类中的this指向
①constructor和render中的this都指向组件实例化对象
②类中方法默认采用严格模式,this指向为undefined
③在render里绑定方法,若不是立即调用,则方法内部this也不指向实例对象(综②③两点结论都一样,方法里的this指向不对要自己手动指定)
修改方法中的this指向实例
①在constructor中使用bind手动修改
constructor(props) { super(props) this.state = { isHot: true, wind: false } // 解决办法:用bind手动设置changeWeather的this指向,且拷贝一份到当前实例对象身上(原型对象上本来有一份,但this为undefined) this.changeWeather = this.changeWeather.bind(this) }
②开发中实际采用赋值形式创建方法,使其直接在实例对象身上,函数再改为箭头函数使this指向函数外面(即实例对象)
changeWeather = () => { const { isHot } = this.state this.setState({ isHot: !isHot }) }
6、三大属性之二:props
用于给类式组件传参,格式直接在组件标签上写,会自动传且保存在足见实力对象的props里
(1)写法
写法1:直接分别写
ReactDOM.render(<Weather name="lss" age="21" />, document.querySelector("#test"))
写法2:{...对象形式的值}
const data={name:"lss",age:"21"} ReactDOM.render(<Weather {...data}/>, document.querySelector("#test"))
ps:在原生js中,①...扩展运算符只能扩展数组等,但不可用于对象;②原生中{...对象},是另外固定写法,作用是拷贝对象
此处可以写{...对象}不是js原生语法,是jsx规定的,且只能用在标签上,就是展开对象数据传props,没有拷贝作用
(2)对参数限制(写在类身上)
要先引入propType库,
<script src="./js/prop-types.js"></script>
对参数限制类型和必要性:
// 注意下面两行propTypes一个小写一个大写, Weather.propTypes = { name: PropTypes.string.isRequired,//name限制字符串类型,必需 age: PropTypes.number }
设置默认值:
Weather.defaultProps = { age: 18//age默认值18 }
(3)函数式组件使用props(了解)
props直接作为函数参数接受,参数限制和默认值只能放在和函数平级
function Weather(props){
}
Weather.propType={
}
(三)ref
react提供的获取真实dom的属性
(1)字符串形式(与vue中完全一样)
缺点:性能低,以后可能废弃
设置:ref="btn1"
render() { return <h1 ref="header1" onClick={this.changeWeather}>今天天气很{this.state.isHot ? "炎热" : "凉爽"}</h1> }
获取:this.refs.btn1
changeWeather = () => { const { isHot } = this.state this.setState({ isHot: !isHot }) console.log(this.refs.header1);//这里 }
(2)回调函数形式
函数默认接受参数是当前dom,ref的回调函数,React会自动调用
设置ref:
render() { return <h1 ref={dom => this.header1 = dom} onClick={this.changeWeather}>今天天气很{this.state.isHot ? "炎热" : "凉爽"}</h1> }
获取:改为直接在实例对象身上拿指定的名称
changeWeather = () => { const { isHot } = this.state this.setState({ isHot: !isHot }) console.log(this.header1);//这里 }
四、函数与事件
(一)高阶函数与科里化
高阶函数指函数参数为函数或返回值为函数的函数
柯里化指函数多层嵌套返回函数,在最内层函数对多层函数参数统一处理的形式
(二)事件
React的事件是重新封装的,所以事件名要写成驼峰命名如onClick/onSubmit
谨记事件右边要传回调函数(即当前不会马上执行的函数),若是立即执行函数则函数返回值也必须是函数,来成为事件的回调函数
ps:即右边函数没有()就是回调函数,有()就不是回调函数,则里面返回函数;
若函数需要传事件对象和其他参数,就要写成{箭头函数},箭头函数获取事件对象,再在函数执行体传其他参数,如下
账号<input type="text" onChange={event => this.formData("userName", event)} /> 密码<input type="text" onChange={event => this.formData("password", event)} />
五、生命周期(旧)
初始阶段:
construsctor()
componentWillMount()
render()
componentDidMount():常用,在此经常做一些页面挂载后的操作如发请求、开启定时器等
更新阶段:
(子组件有)componentWillReceiveProps
shouldComponentUpdate():阀门,只有返回true,才会触发下面真正更新重绘,若不设置默认底层会返回true
componentWillUpdate()
render()
componentDidUpdate()
销毁阶段:
componentWillUnmount():常用,用于做一些收尾工作,如清除定时器等
六、生命周期(新)
官方不再建议使用componentWillMount、componentWillUpdate、和componentWillUnmount、实在要用前面加上UNSAFE_
用getDeriveStateFromProps()和getSnapshotBeforeUpdate来替代前两个will
getDeriveStateFromProps:将props的值转为state,用的少
getSnapshotBeforeUpdate:更新前一瞬间快照,在更新前进行一些操作,必须return值,该值在下一个生命周期componentDidUpdate中第三个参数接收到(前两个一个是更新前props,一个是更新前state)
初始阶段:
construsctor()
getDeriveStateFromProps()
render()
componentDidMount():常用,在此经常做一些页面挂载后的操作如发请求、开启定时器等
更新阶段:
getDeriveStateFromProps()
shouldComponentUpdate():阀门,只有返回true,才会触发下面真正更新重绘,若不设置默认底层会返回true
render()
getSnapshotBeforeUpdate()
componentDidUpdate()