参考Blog
关于React引发的思考
- 声名式开发;
- 组件化开发;
- 可以与其他框架并存;
- 函数式变成,便于前端的自动化测设;
- 单向数据流 父组件向子组件传递的数据具有只读行;
- 视图层框架 结合其他框架工具 Flux和redux等工具管理数据;
使用react脚手架工具快速创建一个项目
- 在目录下打开cmd命令行工具;
- 运行
npx create-react-app my-app
命令,快速创建一个项目(npm的版本需在5.2.0+); - 运行
yarn start
命令,启动项目,并在localhost:3000端口自动打开项目; - 项目成功运行在浏览器客户端,证明react脚手架成功搭建;
JSX语法
定义:通过在js文件引入react的包,可以直接写入html5标签元素,我们称之为jsx语法;
知识点:
1.ReactDOM
内置组件是用来处理jsx语法;
2.通常定义组件名时,我们需要大写首字母,但是对于一般的H5标签,我们需要小写,用来区分组件和h5标签;
3.render函数的返回值,即组件html部分,有且只有一个根元素标签;
4.通常我们引入Fragment
占位符,将html部分进行包裹;
6.通常定义组件名时,我们需要大写首字母,但是对于一般的H5标签,我们需要小写,用来区分组件和h5标签;
7.JSX使用{}
进行包裹,内部可以写变量,三元表达式,也可以放入函数执行的结果;
8.{}
内部不可以写对象或函数,但是可以显示对象里定义的key-value键值对;
9.行内属性style
后面必须是一个对象,使用toString
方法进行转译;
10.react区别于vue框架,是一种单向数据流,只能数据驱动视图;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import React,{Component,Fragment} from 'react';
import ReactDOM from 'react-dom';
class App extends Component {
constructor(props){
super(props);
this.state = {
};
}
render() {
return (
<div>
<h2>hello world</h2>
</div>
);
};
};
ReactDOM.render(<App />, document.getElementById('root'));
render渲染函数
ReactDOM.render(jsx结构,container,callback());
- 第一个参数: 当前操作的dom结构
- 第二个参数: 目标容器
- 第三个参数: 回调函数,会在dom放入容器之后,触发
createElement函数封装
目的: ele
和 nEle
等价1
2
3
4
5
6
7
8
9
10
11let ele = React.createElement(
'h1',
{id:'qqq',className:'www'},
'哈哈哈',
React.createElement('div',null,'呵呵呵')
)
let ele1 = <h1 id='qqq' className='www'>
哈哈哈
<div>呵呵呵</div>
</h1>
代码实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53let fn = function (str){
return str.replace(/[A-Z]/g,function(n){
return '-' + n.toLowerCase()
})
}
class Element {
constructor(type,attr,children){
this.type = type
this.attr = attr
this.children = children
}
render(){
let ele = document.createElement(this.type)
for(let key in this.attr){
switch(key){
case 'htmlFor':
ele.setAttribute('for',this.attr[key]);
break;
case 'className':
ele.setAttribute('class',this.attr[key]);
break;
case 'style':
let str = ''
let obj = this.attr[key];
for(let key in obj){
str += `${fn(key)}:${obj[key]};`
}
str = str.slice(0,str.length-1);
ele.setAttribute('style',str)
break;
default:
ele.setAttribute(key,this.attr[key])
break;
}
}
this.children.forEach(item => {
let nEle = item instanceof Element ? item.render():document.createTextNode(item)
ele.app,endChild(nEle)
nEle = null;
});
return ele
}
}
let react = {
createElement(type,attr,...children){
return new Element(type,attr,children)
}
};
let reactDOM = {
render(ele,container){
container.appendChild(ele.render())
}
};
定义组件
定义:
- 创建一个App类,并继承react中component类的属性,这时候我们就创建一个App的组件;
- 无状态组件 : 没有state属性,通过props属性取得数据;
使用函数定义组件=构造函数
1
2
3
4
5
6
7
8
9
10
11function Person(props){
let {id,className} = props
return(
<div id = {id} className = {className}>
hello world
</div>
)
}
ReactDOM.render(<div>
<Person id = "qqq" className = 'www'></Person>
</div>,document.getElementById('root'))使用class语法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14class Person extends Component {
constructor(props){
super(props)
this.state = {
}
}
render(){
}
}
ReactDOM.render(<div>
<Person id = "qqq" className = 'www'></Person>
</div>,document.getElementById('root'))
组件间的通讯
知识点
:
- react组件中的数据来源 一个是属性(props),一个是状态(state),
- 但是不能直接修改props中的数据,而state中的数据可以修改,但是需要用setState触发render函数;
- 在原生标签上,不能有对象的数据格式;
- 自定义组件,行内属性的值 类型不限, 可以是对象;
- 父组件通过行内属性向内属性向子组件传递数据;
将属性包裹成一个对象,向子组件的constructor函数传递实参
- 子组件通过
this.props
拿到父组件的数据; - 父组件通过自定义属性传递一个函数体,子组件通过
this.props.xxx
(参数),
通过让函数体执行,结合传参数的方式修改父组件数据; - setState函数,能触发render函数重新执行,合并渲染虚拟DOM,在Component的原型上;
<button onClick = {this.props.add2.bind(1111,this.state.str2)}>按钮2</button>
若方法是父组件中定义,那么子组件在调用时,不用在意this的指向问题,只要执行即可
因为方法是在父组件中执行的时候,this已经被规定指向父组件;
事件
- 对应的事件对象,只能在函数执行的过程中可以获取;
- 事件执行完毕后就不能再获取到,React会把它设置成null,节省性能;
- 阻止默认事件 原生JS可以使用
e.preventDefault()
或者e.returnValue = false
(IE的方式); - 在React中,只能使用
e.preventDefault()
; - 若bind后面除this外,有其他参数,则会将默认的事件对象当成最后一个参数,传参到add函数中;
- 改变组件原型函数执行时this指向的三种方法,以下代码为实现方式;
1 | add(n,e){ |
children类似于Vue中的插槽slot
用法:代码实现如下
用途: 使用该组件的人,可以通过children
属性,渲染出组件标签类名内部包裹的内容1
2
3
4
5
6
7
8
9
10
11
12render(){
console.log(this.props.children)
return(<div className=''>
{this.props.children[3] || 'hahaha'}
</div>)
}
ReactDOM.render(<App id = '111'>
"我是你爸爸"
<div>hello</div>
<h1>world</h1>
</App>,window.root)