1.react JSX语法原理
-
react是函数式编程,使用jsx语法来渲染组件。jsx语法是合法的JavaScript代码,看上去和我们平常写的html代码差不多,只不过html代码片段写在了JavaScript里面,这就是jsx语法。
class Header extends Component {
render () {
return (
<div>
<h1>React 小书</h1>
</div>
)
}
}
ReactDOM.render(
<Header />,
document.getElementById('root')
)
- 在
javascript中,每一个DOM元素都可以用JavaScript对象来表示,一个DOM元素一般包含标签名,属性,样式,子元素或内容,这些都可以用合法的JavaScript语法来表示。这个看起来就和vue的render函数一样了,其实vue的render函数也是借鉴了react的jsx语法。我们在写的时候是以标签的形式写的,react.js会自动编译成下面的JavaScript对象来表示,两者表示的结构和信息是一致的。 - 所谓的
jsx就是JavaScript对象,看到这种代码结构的时候,大概就明白这是一个怎样的过程。 - 通常渲染
react组件,先从jsx结构开始,编译成JavaScript结构,然后渲染成DOM结构,再插入到页面。
为什么要有JavaScript这一层,就是因为,在转换的时候,可能不是转换成
DOM可能是转换成react -app(react-native),所以会有JavaScript这一层作中转。
<div class='box' id='content'>
<button>Click</button>
</div>
{
tag: 'div',
attrs: { className: 'box', id: 'content'},
children: [
{
tag: 'button',
attrs: null,
children: ['Click']
}
]
}
2.组件render方法
-
render函数返回jsx结构,类似于vue的template,也是必须有一个唯一顶级元素包裹; - 也可以使用
<Fragment>标签,并列展示多个同级标签而不报错,使用需要引用。 - 在
jsx结构可以插入JavaScript表达式,需要用{ }包裹起来,表达式的结果会渲染到页面,{ }里面可以放任何的表达式,包括jsx结构。jsx也能像普通元素那样赋值,能够作为参数传递。
import React, { Component ,Fragment} from 'react';
render () {
const badWord = <span> is not good</span>
return (
<div>
<h1>
React 小书
{badWord}
</h1>
</div>
)
}
3.组件嵌套
- 定义一个组件,可以在别的组件里面嵌套,就像使用普通的标签一样,和
vue的组件使用类似。多个组件的嵌套就组成了组件树。
注意自定义组件必须要使用大写的字母开头。
class Title extends Component {
render () {
return (
<h1>React 小书</h1>
)
}
}
class Header extends Component {
render () {
return (
<div>
<Title />//嵌套组件
</div>
)
}
}
4.事件绑定
- 在
react.js监听事件形式和原生事件更吻合,也是通过onClick,onChange等事件名前面加on,这点和vue不同,vue是通过@click事件名前面加@来绑定事件。 - 绑定的事件需要写在组件内部,用
{}包裹起来,通过on实现的事件绑定,只能用在普通的html标签,而不能用于组件标签。 - 绑定的事件也会有
event对象,只不过react.js将event对象进行了封装,提供统一的api - 在事件里面不能通过
this访问到当前的实例对象,需要使用bind把实例方法绑定到当前实例上,然后在函数内部就能够访问this实例,在调用的使用不影响传参。
class Everything extends Component{
bodyClick(){
console.log(this)
}
render(){
return (
<div onClick={this.bodyClick.bind(this)} className="Header" style={bodyStyle}>
我是身体
</div>
)
}
4.类名ID样式设置
-
react.js的类名不能直接在标签内使用class来设置,需要使用className来设置类名,id是可以直接设置。 - 一些自定义的属性名也可以直接在标签内设置,
- 设置
css样式不能直接写在行内,可以使用类名,id外部映入的css文件设置样式,行内样式可以使用变量的形式来设置。或者使用双引号包裹,以json的形式书写。 -
label标签绑定for的时候不能直接使用for,必须使用htmlFor。
react.js在解析的时候遇见<会解析为html,遇见{会以javascript解析。所以不能放在""里面。
class Body extends Component {
render() {
let bodyStyle={
color:"blue",
height:"100px",
fontSize:"20px",
lineHeight:"100px"
}
return (
<div data-name="der" id="der" className="Header" style={bodyStyle}>
<h1 style={{fontSize:"50px"}}>today</h1>
</div>
);
}
}
5,组件state状态设置
- 每一个组件都会有一个自己的数据状态(state),类似于
vue的data,用来存储组件的数据状态。 - 设置
state状态在construstor里面设置,constructor方法是es6类的默认方法,一个类必须要有一个constructor方法,默认返回实例对象(this)。 - 改变
state是使用setState方法,它接受一个对象或者一个函数作为参数,作为一个对象的时候,传入更改的部分即可,但是会有一个问题,调用setState并不会立即执行,所以在改变state的函数里面打印的还是旧的值,但是新的值已经渲染到页面。 - 函数作为
setState的参数的时候,有时候在函数里面需要使用改动之后的值,就得用函数作为参数
constructor(){
super()
this.x=123;
this.y=123;
this.state={
name:"xiaoming",
flag:false
}
}
bodyClick(e){
this.setState({
name:"123",
flag:!this.state.flag
})
this.setState((prevState)=>{
console.log(prevState)//name:123,flag:true可以获取到改动之后的值。
})
}
6,props组件传参
- 使用
props和vue的差不多,只不过react的props不需要v-bind,直接按照标签属性的格式书写就行。 - 在接收
props的组件内通过this.props.参数名来访问传进来的参数,传进来的参数在接收组件内是无法更改的,只能在传入组件更改。 -
props可以传出的参数类型包括对象,数组,函数,等类型, -
props也可以像vue设置默认值,不传的时候使用默认值。 -
props传的是和render同级的函数时需要bind(this),确定this指向。
class Body extends Component {
bodyClick(e){
console.log(this.props)
if(this.props.fun){
this.props.fun();
}
}
static defaultProps = {//设置默认值
title: '取消',
unlikedText: '点赞'
}
render() {
return (
<div onClick={this.bodyClick.bind(this)} className="Header">
<h1>{this.props.content.name}{this.props.title?this.props.title:"failed"}</h1>
</div>
);
}
}
class App extends Component {
render() {
return (
<div className="App">
<Body der={['123']} fun={()=>{console.log("传了个函数")}} content={{name:"name"}} title="props标题"></Body>
</div>
);
}
}
7.列表数据渲染
-
react的数据渲染没有vue那么的方便,一个v-for就可以搞定了,react数据渲染有多种方式,第一种是手动for循环,第二种使用map方法, -
react数据循环也需要一个唯一标志符key。
第一种
class Other extends Component{
render(){
let arr=['第一页','第一页','第一页','第一页','第一页','第一页','第一页','第一页',]
let array=[]
arr.forEach((item,index)=>{
array.push( <div className={index===0?'navActive menu-list':'menu-list'} key={index}>{item}</div>)
})
return (
<div className="left-menu-wrapper">
{ array}
</div>
)
}
}
第二种
class Other extends Component{
render(){
let arr=['第一页','第一页','第一页','第一页','第一页','第一页','第一页','第一页',]
let array=arr.map((item,index)=>{
return <div className={index===0?'navActive menu-list':'menu-list'} key={index}>{item}</div>
})
return (
<div className="left-menu-wrapper">
{ array}
</div>
)
}
}
第三种
render(){
let arr=['第一页','第一页','第一页','第一页','第一页','第一页','第一页','第一页',]
return (
<div className="left-menu-wrapper">
{
arr.map((item,index)=>{
return <div onClick={this.navTab} className={index===0?'navActive menu-list':'menu-list'} key={index}>{item}</div>
})
}
</div>
)
}
8.生命周期
-
react在组件渲染并插入到页面会有一个生命周期,和vue的生命周期类似。可以像render一样定义在组件的内部。 -
contrustor组件内部的状态初始化都是在这里面进行,state也是放在了里面。 -
componentWillMount在render函数之前调用。 -
componentDidMount在render函数调用之后调用。 -
componentWillUnmount组件删除的时候调用。 -
componentWillUpdate组件重新渲染时开始调用。 -
componentDidUpdate组件更新完毕时调用。 -
componentWillReceivePropsprops改变时调用。 -
shouldComponentUpdate控制组件是否重新渲染。
class Toder extends Component{
constructor(){
super();
this.contentArr=[];
this.state={
contentArr:[]
}
}
UNSAFE_componentWillReceiveProps(nextProps){
console.log("props改变")
}
UNSAFE_componentWillMount(){
console.log("组件开始渲染")
}
UNSAFE_componentWillUpdate(){
console.log("组件重新渲染")
}
UNSAFE_componentDidUpdate(){
console.log("组件重新渲染完毕")
}
componentWillUnmount(){
console.log("组件销毁")
}
render(){
return (
<div className="comment-wrapper">
</div>
)
}
}
9.DOM操作
- 虽然
react提供了很多的方法进行事件监听,有些功能的实现避免不了DOM的操作,所以需要使用ref来操作DOM。 -
ref为回调函数的时候,函数的参数就是当前的DOM,当元素挂载完成之后,就会执行函数。 -
ref为字符串的时候可以通过this.refs.字符串访问DOM - 可以给
html标签加ref,也可以给组件加ref。 - 一般不提倡操作
DOM
函数
<button ref={(dom)=>{console.log(dom)}} >点击</button>
字符串
<div ref="ggg" className="comment-wrapper">
</div>
10.容器类组件
- 容器类组件顾名思义就是将一个组件当做一个容器,动态的向里面插入内容。
- 实现原理就是通过
props向容器组件传入html标签结构,在容器组件内通过this.props渲染出来,传入的html结构可以访问到定义props组件的state,也能触发方法。这样通过一个容器组件就能复用很多的代码,
定义props组件
class Body extends Component {
constructor(){
super();
this.state={
title:"123"
}
}
btnClick(){
console.log(this.state)
}
render() {
let content=<div>
<input placeholder="请输入内容" type="text"/>
<button onClick={this.btnClick.bind(this)}>删除</button>
</div>
return (
<div className="body-container">
<Toder content={content} title={this.state.title}></Toder>
</div>
);
}
}
容器组件
class Toder extends Component{
constructor(){
super();
this.contentArr=[];
this.state={
contentArr:[]
}
}
UNSAFE_componentWillMount(){
console.log(this.props.content.props)
}
render(){
return (
<div>
<div style={{backgroundColor:"skyblue"}}>{this.props.content.props.children[0]}</div>
<div style={{backgroundColor:"pink"}}>{this.props.content.props.children [1]}</div>
</div>
)
}
}
11.渲染html字符串
-
react里面要渲染一个类似于html的字符串是会转义,防止xss攻击,所以要讲字符串以html标签的形式渲染出来,需要使用dangerouslySetInnerHTML.
注意标签中间不能有任何内容包括空格和换行。
render(){
return (
<div dangerouslySetInnerHTML={{__html: this.state.text}}></div>
)
}
12. 验证props
- 验证
props是非常有必要的,大项目开发能少走很多弯路。 - 验证
props使用react自带的prop-types,可以验证传的props的数据类型,以及是否必须传值。 -
isRequired表示必须传值。 - 常用的验证数据类型有
number,string,boolean,object。
先引入
import PropTypes from "prop-types"
再设置验证
class Item extends Component {
constructor(){
super()
this.state={
}
}
handleClick(){
this.props.delItem(this.props.index)
}
render() {
return (
<li onClick={this.handleClick.bind(this)}>{this.props.item}</li>
);
}
}
Item.propTypes={
index:PropTypes.number.isRequired
}







网友评论