[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);
//組件有兩個數據源 一個是屬性 外界傳遞的 還有一個叫狀態是自己的
//都會導致頁面刷新
// 你傳遞的屬性可能不是我預期的
```
## 組件通信

## 關于React.createElement

```
//編輯后就是
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

### getSnapshotBeforeUpdate


## react-redux
如果老的狀態和新的狀態時同一個(地址)

`react-redux`是不會允許更新視圖的

## 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);
```
可以發現下面第二層的數據不大對

多層使用`fromJS`


嵌套多層時 改變深層的屬性
```
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);
```

```
console.log(m1.a)
<<<
undefined
```
可以使用`toJS`方法將immutable對象轉換為普通js對象

兩個`immutable`對象一定是不相同的,但如果我們想要比較兩個對象中的值一不一樣,可以使用`is()`方法

### immutable在react中的應用

### redux-immutable

不再用redux里的cmobineReducers


- 空白目錄
- 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