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
组件更新完毕时调用。 -
componentWillReceiveProps
props改变时调用。 -
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
}
网友评论