[toc]
## 转换过程:jsx->React.createElement->{虚拟dom}
```
import React from 'react'; //这个名字不能随便改 因为编译后就叫这个名字 看77行
import ReactDOM,{render} from 'react-dom';
//jsx语法时facebook自己发明的 babel-preset-react
let ele = <h1 className="read"><span>zfpx</span>hello,world</h1>;
//以上等同于以下
// type,props,children
React.createElement(
"h1" //type
,{
className:'read'
}
,React.createElement(
"span"
,null
,"zfpx"
)
,"hello,world"
);
// ->
// let obj = {
// type:'h1'
// ,props:{
// className:'red'
// ,children:[
// {type:'span',props:{children:'zfpx'}}
// ,'hello,world'
// ]
// }
// }
```
## prop-types和属性验证
```
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
let person = {
name:'ahhh'
,age:111
,gender:'男'
,hobby:['sleeping']
,salary:100
}
class Person extends Component{
// Person.propTypes =
static propTypes = {
name:PropTypes.number.isRequired
,age:PropTypes.number
,gender:PropTypes.oneOf(['男','女'])
,hobby:PropTypes.array
,salary:function(props,keyName,componentName){
if(props[keyName]<1000){
throw new Error(`${componentName}error${props[keyName]}is too low`) //Person error 100 is too low
}
}
,position:PropTypes.shape({
x:PropTypes.number
,y:PropTypes.number
})
}
constructor(props){
super();
}
render(){
let{name,age,gender,hobby,salary,position} = this.props;
return(
<div>
{this.props.name}
</div>
)
}
}
```
## React.createElement和ReactDOM.render 原理
```
class Element{
constructor(type,props){
this.type = type;
this.props = props;
}
}
let React = {
createElement(type,props,...children){
if(children.length === 1)children = children[0];
return new Element(type,{...props,children});
}
};
function render(eleObj,container){
let {type,props} = eleObj;
let ele = document.createElement(type);
for(let key in props){
if(key!=='children'){
if(key === 'className'){
ele.setAttribute('class',props[key]);
}else{
ele.setAttribute(key,props[key]);
}
} else{
// 是我们的儿子节点
let children = props[key];
if(Array.isArray(children)){
// 是数组
children.forEach(child=>{
if(child instanceof Element){
render(child,ele);
}else{
ele.appendChild(document.createTextNode(child));
}
});
}else{
if(children instanceof Element){
render(children,ele);
}else{
ele.appendChild(document.createTextNode(children));
}
}
}
}
container.appendChild(ele);
}
// render(ele,window,root);
```
## JSX
```
import React from 'react'; //这个名字不能随便改 因为抽象语法树编译后就是React React.createElement
import ReactDOM,{render} from 'react-dom';
//jsx和html写法不完全一样
// className ->class
// htmlFor -> label的for
// jsx元素可以嵌套
//相邻的react元素 不能不被包裹使用 必须加一层标签
//jsx里面可以放js 里面区分是不是js根据的是{}
let name = ''
let ele = (
<React.Fragment>
<label htmlFor="a"></label>
<input type="text" id='a'/>
<h1>
{/*注释*/}
{name}{age}
{function name(params) {return 100}()}
{1+3}{1==1?'2':'3'}
</h1>
<h1 style={{background:'red'}}>hello</h1>
<div dangerouslySetInnerHTML={{__html:'<h1>hello ahhh</h1>'}}></div> {/*相当于innerHtml*/}
</React.Fragment>
);
render(ele,window.root);
```
## render第一个参数放函数
```
//渲染函数
import React from 'react';
import ReactDOM from 'react-dom';
//1)
function school(name,age){
return <h1>{name}{age}</h1>
}
ReactDOM.render(school('ahhh',111), document.getElementById('root'));
//2)
let el = (
<ul>{school('ahhh',111)}</ul>
)
ReactDOM.render(el,window.root)
//3)
let dinner = ['汉堡','可乐','薯条'];
let eleObj = dinner.map((item,index)=>(
<li key={index}>{item}</li>
));
ReactDOM.render(eleObj,window.root);
```
## 组件
```
//组件分两种 函数组件(函数)function 类组件 class
//函数组件中没有this 没有声明周期 没有状态
import React from 'react';
import ReactDOM from 'react-dom';
//怎么区分是组件还是jsx元素
//如果名字是大写就是组件,小写就是jsx元素
//组件必须要有返回值 也可以返回null null也是合法的
function School(props){
// return null
return <h1>{props.name}{props.age}</h1>
}
//School({name:'ahhh',age:111});
//组件可以通过属性传递数据
ReactDOM.render(<School name='ahhh' age='111'/>, document.getElementById('root'));
```
## 函数组件和类组件与时钟示例
```
import React from 'react';
import ReactDOM from 'react-dom';
function Clock(props){
return (
<div>
<span>当前时间:</span>
{props.date.toLocaleString()}
</div>
)
}
//不会一直渲染 只渲染一次
ReactDOM.render(<Clock date={new Date()}/>, document.getElementById('root'));
//组件的特点 就是复用 多次使用
setInterval(function(){
ReactDOM.render(<Clock date={new Date()}/>, document.getElementById('root'));
},1000);
```
```
import React from 'react';
import ReactDOM from 'react-dom';
class Clock extends React.Component{
constructor(){
super();
this.state = {date:new Date().toLocaleString(),name:'ahhh'}
}
// state = {date:new Date().toLocaleString()}
//如果用类组件需要提供一个render方法
// 组件渲染完成后会调用这个生命周期
componentDidMount(){
setInterval(()=>{
this.setState({date:new Date.toLocaleString()});
},1000);
}
render(){
return (
<span>时间是:{this.state}</span>
)
}
}
ReactDOM.render(<Clock/>,window.root);
//组件有两个数据源 一个是属性 外界传递的 还有一个叫状态是自己的
//都会导致页面刷新
// 你传递的属性可能不是我预期的
```
## 组件通信
![](https://box.kancloud.cn/86d0db46d19ab323795317e46ed96df1_744x111.png)
## 关于React.createElement
![](https://box.kancloud.cn/1928509184762f9f6e89383ad0bc6d92_668x75.png)
```
//编辑后就是
React.createElement //大写的React
```
## 父组件会在子组件DidMount后才DidMount(包括父组件重新Mount,子组件也会重新Mount,然后父组件才DidMount)
## 16.3新特性
### React.createRef()
```
export default class xxx extends React.Component{
constructor(){
super();
this.text = React.createRef();
}
componentDidMount(){
// this.text.focus();
this.text.current.focus();
}
render(){
return (
<div>
{/*<input type="text" ref={(input)=>{this.text=input}}/>*/}
{/*会自动的将当前输入框 放在this.text.current*/}
<input type="text" ref={this.text}/>
</div>
)
}
}
```
### getDerivedStateFromProps
![](https://box.kancloud.cn/209e765566e1c1b426b91f04d6093722_586x366.png)
### getSnapshotBeforeUpdate
![](https://box.kancloud.cn/99fee69979284c8fc86226b3a4cb772b_476x237.png)
![](https://box.kancloud.cn/08bc9a257cc90acfe3726b788c16c014_844x155.png)
## react-redux
如果老的状态和新的状态时同一个(地址)
![](https://box.kancloud.cn/221c7aed8422289df2b6931321bc4b59_663x311.png)
`react-redux`是不会允许更新视图的
![](https://box.kancloud.cn/f99e02d6e8aba9fe74f589c9a1939503_561x288.png)
## immutable.js
```
let {Map} = require('immutable');
// 导入immuatable
//1.只操作对象
let obj = {a:1};
//返回的m1 就是不可变对象,永远不会变
let m1 = Map(obj);
```
set
```
// let m2 = m1.set('a',100); //调用set后永远返回的都是一个新的不可变对象
```
update
```
let m2 = m1.update('a',(a)=>a+100);
console.log(m1.get('a'));
console.log(m2.get('a'));
```
Map 只处理一层
```
let obj = {a:{a:1},b:2};
let m1 = Map(obj);
console.log(m1);
```
可以发现下面第二层的数据不大对
![](https://box.kancloud.cn/6188d073bbd4a29c473e5aafd8fe5d5d_456x92.png)
多层使用`fromJS`
![](https://box.kancloud.cn/d7a7bc1f40aa96433df150c5c05dffce_556x213.png)
![](https://box.kancloud.cn/5087b133a8a5e0c3f4dcb07d8dbdfffe_556x206.png)
嵌套多层时 改变深层的属性
```
let {Map,fromJS} = require('immutable');
let obj = {a:{b:{c:{d:1},d:100},m:100}};
let m1 = fromJS{obj};
m1.setIn(['a','b','c','d'],2); // ->a.b.c.d = 2 并且返回新对象
```
getIn
```
console.log(m1.getIn(['a','b','c','d']));
```
immutable 支持对数组操作
List -> 相当于操作对象时的Map
多层级时仍然使用`fromJS`
```
let m1 = List([[1,2,3],[4,5,6]])
let m1 = fromJS([[1,2,3],[4,5,6]])
```
`immutable`对象不可直接访问其属性
```
let m1 = fromJS({a:1});
console.log(m1);
```
![](https://box.kancloud.cn/35705e59f5137c6cbb5f6d229f9f803c_243x88.png)
```
console.log(m1.a)
<<<
undefined
```
可以使用`toJS`方法将immutable对象转换为普通js对象
![](https://box.kancloud.cn/df02396d7529850c20e7fb9f4764fabd_377x340.png)
两个`immutable`对象一定是不相同的,但如果我们想要比较两个对象中的值一不一样,可以使用`is()`方法
![](https://box.kancloud.cn/53c06437469862602b7b1d0aad215e78_352x120.png)
### immutable在react中的应用
![](https://box.kancloud.cn/e7e30186b9295c66a1ee44c8e4b471cc_643x528.png)
### redux-immutable
![](https://box.kancloud.cn/b05954dccfe61182b422db194beec291_545x60.png)
不再用redux里的cmobineReducers
![](https://box.kancloud.cn/d2136d6920c1873a1010e9f07cfddbc8_641x207.png)
![](https://box.kancloud.cn/37e4bf9032d6a73aa3681521fdace493_666x232.png)
- 空白目录
- 01.JSX,了解一下?
- JSX与虚拟DOM
- React
- 02.React文档精读(上)`
- React路由
- 关于BrowserRouter
- 关于Route
- 应用
- 权限认证
- case1
- context
- 新context
- 03.React路由
- 04.Diff
- 05.styled-components
- redux设计思想与API
- redux实现1
- 06.redux2
- 06.redux3
- 关于状态初始化
- saga
- 新版
- 使用saga进行业务逻辑开发
- react-router-redux
- React性能优化
- immutable使用
- 未整理
- FAQ
- 常用中间件
- pureComponent
- 项目相关总结
- antd分尸
- 按需加载
- ReactWithoutJSX
- 我的组件库
- C领域
- 用户接口
- htmlType
- style
- show
- conjure
- grid
- inject
- stop
- 内部接口
- 衍生组件
- Button
- 报错集锦
- ReactAPI
- 类上的那些属性
- prop-types
- React.createElement
- React.cloneElement
- React.Children和props.children
- react元素和react组件关于作为children方面的那些问题
- react组件与虚拟dom
- ref