17、React真實DOM和虛擬DOM|缺點和優點|子組件向父組件傳值|React組件3個部分|ref可以設置回調函數|為什么不能用index做key|狀態提聲|跨多級組件傳參原理、react之約束|受控組件、setState、生命周期、組件寫法、插槽、react.15.6.0.js源碼外框、ant-design-pro構成、前端路由及觸發條件


一、真實DOM和虛擬DOM|缺點和優點|子組件向父組件傳值|React組件3個部分|ref可以設置回調函數|為什么不能用index做key|狀態提聲|跨多級組件傳參原理
1、真實DOM和虛擬DOM
(1)真實DOM,用戶每次操作DOM(文檔對象模型),都會引起BOM(瀏覽器對象模型)重新渲染
(2)虛擬DOM,用戶每次操作DOM(文檔對象模型),都會改變虛擬DOM(堆內存的一個對象),最后一次性地渲染到BOM上。
2、React的缺點和優點  
(1)缺點:
(A)React本身只是一個V,不是一個完整的框架,不是一套完整的框架
(B)需要加上React-Router和React-Redux才能成為一套完整的框架  
(2)優點:
(A)單向數據流動;
(B)虛擬DOM取代物理DOM作為操作對象;
(C)用JSX語法取代HTML模板,在JavaScript里聲明式地描述UI。  
3、react子組件向父組件傳值
(1)react父組件向子組件傳值:屬性傳參
(2)react子組件向父組件傳值:在父組件定義一個函數並綁定父組件的this,在函數體里,將函數的參數賦值給父組件this的一個屬性;通過屬性傳參的方式把這個函數傳給子組件。在子組件里,給這個函數傳參並執行,實現子組件向父組件傳值!
4、React組件3個部分
(1)React組件基本上由3個部分組成——屬性(props)、狀態(state)以及生命周期方法
(2)React組件一旦接收到的參數(即props)或自身狀態有所改變,React組件就會執行相應的生命周期方法,最后渲染。
(3)整個過程完全符合傳統組件所定義的組件職責(“屬性更新”與“狀態改變”)。
(4)以上內容來自《深入React技術棧》第18和30頁。
5、ref可以設置回調函數
(1)<input type="text" ref="myInput"/>
this.refs.myInput.value ="22"; //this.$refs.myInput.value ="22"  減少獲取dom節點的消耗2)ref屬性可以設置為一個回調函數,這也是官方強烈推薦的用法;這個函數執行的時機為:
(3)組件被掛載后,回調函數被立即執行,回調函數的參數為該組件的具體實例。
(4)組件被卸載或者原有的ref屬性本身發生變化時,回調也會被立即執行,此時回調函數參數為null,以確保內存泄露。
6、為什么不能用index做key?1)react會根據key來決定是否重新構建該組件
(2)刪除和添加操作,會使一個組件使用另一個的組件的index,進而key,進而data
7、狀態提聲(父組件的函數作為屬性傳給子組件)
(1)在父組件的constructor中定義狀態
(2)在父組件的方法中執行this.setState({})
(3)把父組件的方法作為屬性fromParent傳給子組件
(4)在子組件的方法中加上this.props.fromParent(e.target.value);
(5)觸發子組件的事件,執行子組件的方法,改變父組件的狀態
8、跨多級組件傳參原理
//祖父組件聲明自己支持 context
static childContextTypes = {
  color:PropTypes.string,
  callback:PropTypes.func,
}
//祖父組件提供一個函數,用來返回相應的 context 對象
getChildContext(){
  return{
    color:"red",
    callback:this.callback.bind(this)
  }
}
//孫子組件聲明自己需要使用 context
static contextTypes = {
  color:PropTypes.string,
  callback:PropTypes.func,
}

二、約束性組件和非約束性組件(受控組件和非受控組件)
1、約束性組件
<input type="text" value={this.state.name} onChange={this.handleChange} />
handleChange: function(e) {
  this.setState({name: e.target.value});
}
//用戶輸入內容A>觸發onChange事件>handleChange中設置state.name="A"渲染input使他的value變成A
2、非約束性組件
<input type="text" defaultValue="a" />//用戶輸入A -> input 中顯示A 
3、React 把 input,textarea 和 select 三個組件做了抽象和封裝,他們有統一的 value 屬性 和 onChange 事件。
<input type='text' name='intro' id='intro' value={this.state.email} onChange={this.handleEmail} />
<textarea type='text' name='intro' id='intro' value={this.state.intro} onChange={this.handleIntro} />
<textarea type='text' name='intro' id='intro' value={this.state.intro} onChange={this.handleIntro} />
4、checkbox改變的不是 value ,而是 checked 狀態。
<input type='radio' name='gender' checked={this.state.male==='MALE'} onChange={this.handleGender} value='MALE' />
<input type='radio' name='gender' checked={this.state.male==='FEMALE'} onChange={this.handleGender} value='FEMALE' />
handleGender(e){
  this.setState({
    male:e.target.value
  })
}

三、setState
1this.setState接收兩種參數
(1)對象+函數(可選):傳入的對象淺層合並到新的state中
(2)函數+函數(可選):第一個函數接受兩個參數,第一個是當前state,第二個是當前props,該函數返回一個對象,和直接傳遞對象參數是一樣的,就是要修改的state;第二個函數參數是state改變后觸發的回調。
2this.setState何時同步何時異步?
(1)異步,由react控制的事件處理程序
(2)同步,react控制之外的事件中調用setState是同步更新的。比如原生js綁定的事件,setTimeout/setInterval等。
(3)大部分開發中用到的都是react封裝的事件,比如onChange、onClick、onTouchMove等,這些事件處理程序中的setState都是異步處理的。
3this.setState何時渲染
(1)死循環:this.setState執行時,會根據_compositeLifeCycleState是否為null,來決定是否重新渲染,因此在有的生命周期里,會產生死循環。
(2)只生效一次:this.setState最后執行隊列時,先用變量獲取並存儲state,后來直接修改變量,最后把變量賦值給state,頁面渲染。
handleClick() {
  //const count = this.state.count 下面 this.setState 多次執行,但只生效一次。因為似乎存在此行代碼。
  this.setState({
    count: count + 1
  })
  this.setState({
    count: count + 1
  })
}

四、React生命周期
1、React15、React16完整生命周期比較
A、實例化
(1)React15之ES5寫法:propTypes = {}; getDefaultProps(){return{}};
  //React16之ES6寫法:static propTypes = {}; static defaultProps = {}; 2)React15之ES5寫法:getInitialState(){return{}};
  //React16之ES6寫法:constructor3)React15之ES5寫法:componentWillMount//執行setState會合並到初始化狀態中;獲取從屬性生成的狀態;此后生命狀態會被重置為null;
  //React16之ES6寫法:static getDerivedStateFromProps//執行setState會合並到初始化狀態中;獲取從屬性生成的狀態4)render//執行setState會發起updateComponent導致-死循環5)componentDidMount//執行setState會導致更新;這是發起異步請求去API獲取數據的絕佳時期
B、存在期
(1)React15之ES5寫法:componentWillReceiveProps//執行setState會合並到狀態中;此后生命狀態會被重置為null
  //React16之ES6寫法:static getDerivedStateFromProps//執行setState會合並到狀態中;2)shouldComponentUpdate//執行setState會發起updateComponent導致-死循環3)React15之ES5寫法:componentWillUpdate//執行setState會發起updateComponent導致-死循環
  //React16之ES6寫法:此處沒有componentWillUpdate4)render//執行setState會發起updateComponent導致-死循環
  //React16之ES6寫法:此處新增getSnapshotBeforeUpdate//執行setState會發起updateComponent導致-死循環5)componentDidUpdate//可以有條件地執行setState
C、銷毀期
(1)componentWillUnmount//等待頁面卸載,改變state沒意義。
2、React16生命周期(過渡)
(1)沿用了3個componentWillMount,componentWillReceiveProps,componentWillUpdate
(2)新增了2個getDerivedStateFromProps,getSnapshotBeforeUpdate
(3)在實際項目中,沿用方案和新增方案只能二選一,不能混用
3、React17生命周期(全新)
(1)棄用了3個componentWillMount,componentWillReceiveProps,componentWillUpdate
(2)啟用了2個getDerivedStateFromProps,getSnapshotBeforeUpdate
(3)新增了1個componentDidCatch(處理錯誤)
來源:https://blog.csdn.net/liuqiao0327/article/details/107297106

五、React組件寫法
1、React15.6.1版組件之ES5寫法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React實例</title>
<script src="https://lib.baomitu.com/react/15.6.1/react.js"></script>
<script src="https://lib.baomitu.com/react/15.6.1/react-dom.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
var Button = React.createClass({
  setNewNumber(number,event) {
    this.setState({number: this.state.number + 1})
  },
  getDefaultProps() {
    return { name: "計數器" };
  },
  getInitialState() {
    return{number: 0};
  },
  render() {
    return (
      <div>
        <button onClick = {this.setNewNumber.bind(null,this.state.number,event)}>點擊{this.props.name}</button>
        <Text myNumber = {this.state.number}></Text>
      </div>
    );
  }
})
var Text = React.createClass({
  //一、以下實例化時期
  getDefaultProps() {
    console.log("1.getDefaultProps 獲取默認屬性");
    return { };
  },
  getInitialState() {
    console.log("2.getInitialState 獲取初始狀態");
    return { };
  },
  componentWillMount() {
    console.log("3.componentWillMount 此組件將要被渲染到目標組件內部");
  },
  componentDidMount() {
    console.log("5.componentWillMount 此組件已經被渲染到目標組件內部");
  },
  //二、以下存在時期
  componentWillReceiveProps() {
    console.log("6.componentWillReceiveProps 此組件將要收到屬性");
  },
  shouldComponentUpdate(newProps, newState) {
    console.log("7.shouldComponentUpdate 組件是否應該被更新");
    return true;
  },
  componentWillUpdate() {
    console.log("8.componentWillUpdate 組件將要被更新");
  },
  componentDidUpdate() {
    console.log("10.componentDidUpdate 組件已經更新完成");
  },
  //三、以下銷毀時期
  componentWillUnmount() {
    console.log("11.componentWillUnmount 組件將要銷毀");
  },
  render() {
    console.log("4和9.render 組件將要渲染");
    return (
      <div>
        <h3>{this.props.myNumber}</h3>
      </div>
    );
  }
})
ReactDOM.render(
   <div>
      <Button />
   </div>,
  document.getElementById('example')
);
</script>
</body>
</html>
2、React16.4.0版組件之ES6寫法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React實例</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
class Button extends React.Component {
  //name="計算器";state = {number: 0};
  //上下寫法,二選一
  constructor(props) {
    super(props);
    this.name="計算器";
    this.state = {number: 0};
  };
  setNewNumber(number,event) {
    this.setState({number: this.state.number + 1})
  };
  render() {
    return (
      <div>
        <button onClick = {this.setNewNumber.bind(this,this.state.number,event)}>點擊{this.name}</button>
        <Text myNumber = {this.state.number}></Text>
      </div>
    );
  }
}
class Text extends React.Component {
  //一、以下實例化時期
  constructor(props) {
    super(props);
    console.log("2.constructor 獲取初始狀態");
  }
  componentWillMount() {
    console.log("3.componentWillMount 此組件將要被渲染到目標組件內部");
  }
  componentDidMount() {
    console.log("5.componentWillMount 此組件已經被渲染到目標組件內部");
  }
  //二、以下存在時期
  componentWillReceiveProps() {
    console.log("6.componentWillReceiveProps 此組件將要收到屬性");
  }
  shouldComponentUpdate(newProps, newState) {
    console.log("7.shouldComponentUpdate 組件是否應該被更新");
    return true;
  }
  componentWillUpdate() {
    console.log("8.componentWillUpdate 組件將要被更新");
  }
  componentDidUpdate() {
    console.log("10.componentDidUpdate 組件已經更新完成");
  }
  //三、以下銷毀時期
  componentWillUnmount() {
    console.log("11.componentWillUnmount 組件將要銷毀");
  }
  render() {
    console.log("4和9.render 組件將要渲染");
    return (
      <div>
        <h3>{this.props.myNumber}</h3>
      </div>
    );
  }
}
ReactDOM.render(
   <div>
      <Button />
   </div>,
  document.getElementById('example')
);
</script>
</body>
</html>
來源 https://www.runoob.com/try/try.php?filename=try_react_life_cycle2
 
六、插槽
1、portal插槽
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React插槽實例</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
  <div id="container"></div>
  <div id="outer"></div>
</body>
<script type="text/babel">
const container = document.getElementById('container');
const outer = document.getElementById('outer');
class Modal extends React.Component {
  constructor(props) {
    super(props);
    this.div = document.createElement('div');
  }
  componentDidMount() {
    outer.appendChild(this.div);
  }
  componentWillUnmount() {
    outer.removeChild(this.div);
  }
  render() {
    return ReactDOM.createPortal(
      this.props.children,
      this.div
    );
  }
}
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {clicks: 0};
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState(state => ({
      clicks: state.clicks + 1
    }));
  }
  render() {
    return (
      <div onClick={this.handleClick}>
        <div>{this.state.clicks}</div>
        <div><button>Click</button></div>
        <Modal>
          <div>
            <button className="modal">Click</button>
          </div>
        </Modal>
      </div>
    );
  }
}
ReactDOM.render(<Parent/>, container);
</script>
2、React.Children插槽
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>React插槽實例</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
  <div id="container"></div>
  <div id="outer"></div>
</body>
<script type="text/babel">
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {clicks: 0};
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick(event) {
    console.log(event)
    this.setState(state => ({
      clicks: state.clicks + 1
    }));
  }
  render() {
    var that = this;
    return (
      <div>
        <div>{this.state.clicks}</div>
        <div><button onClick={this.handleClick}>clicks</button></div>
        <ul>
          {
            React.Children.map(this.props.children,function(item,index){
              if(index !=1){
                return <li onClick={that.handleClick}>{item}</li>
              }else{
                return <li onClick={that.handleClick}>{item}---{index+1}</li>
              }
            })
          }
        </ul>
      </div>
    );
  }
}
ReactDOM.render(<Parent>
  <span style={{cursor:'pointer',userSelect: 'none'}}>插槽一</span>
  <span style={{cursor:'pointer',userSelect: 'none'}}>插槽二</span>
  <span style={{cursor:'pointer',userSelect: 'none'}}>插槽三</span>
</Parent>, document.getElementById('container'));
</script>
</html>

七、React.15.6.0源碼外框
/**
 * React v15.6.0
 */
(function (allFn) {
  if (typeof exports === "object" && typeof module !== "undefined") {
    module.exports = allFn()
  } else if (typeof define === "function" && define.amd) {
    define([], allFn)
  } else {
    var tempGlobal;
    if (typeof window !== "undefined") {
      tempGlobal = window
    } else if (typeof global !== "undefined") {
      tempGlobal = global
    } else if (typeof self !== "undefined") {
      tempGlobal = self
    } else {
      tempGlobal = this
    }
    tempGlobal.React = allFn()
  }
})(function () {
  var define, module, exports;
  return (function outerFn(first, second, third) {
    function recursion(number) {
      if (!second[number]) {
        if (!first[number]) {
          var error = new Error("Cannot find module '" + number + "'");
          throw error.code = "MODULE_NOT_FOUND", error
        }
        var module = second[number] = {
          exports: {}
        };
        first[number][0].call(module.exports, function (key) {
          var value = first[number][1][key];
          return recursion(value ? value : key)
        }, module, module.exports, outerFn, first, second, third)
      }
      return second[number].exports//在react實例化的過程中,這行代碼不但因獲取依賴而多次執行,而且還因獲取react實例而最后執行。
    }
    for (var number = 0; number < third.length; number++) recursion(third[number]);//fn(16)第1次執行,執行結果沒有變量接收
    return recursion //執行到這,整個邏輯就快結束了。前兩行可以合並為一行:return recursion(third[0]),同時下面的"(48)"應當刪掉。 
  })({ 2: [function (_dereq_, module, exports) { var thisVar = _dereq_(138) }, { "25": 25, "30": 30 }], }, {}, [16])(16)// fn(16)第2次執行,因為n[num]為真,所以直接返回n[num].exports並被掛在g.React上 
});
 
八、ant-design-pro腳手架的構成
Pro的底座是umi,umi是一個(基於)webpack之上的(自動化)整合工具。
Pro的核心是umi,umi的核心是webpack。
1、web 技術
2、Umi-前端應用框架(可整個或部分復用的軟件)
(1)Node.js 前端開發基礎環境
(2)Webpack 前端必學必會的打包工具
(3)React Router 路由庫,被dva內置
(4)proxy 反向代理工具
(5)dva 輕量級的應用框架(可整個或部分復用的軟件)
(6)fabric 嚴格但是不嚴苛的 lint 規則集
(7)TypeScript 帶類型的 JavaScript
3、Ant Design 前端組件庫
4、ProComponents 模板組件
5、useModel 簡易數據流
6、編譯時和運行時
(1)編譯時,環境是node環境,可以使用fs,path等功能;沒有使用webpack,不能使用jsx,不能引入圖片
(2)運行時,編譯完成,開始在瀏覽器環境運行,不能使用fs、path,有跨域的問題;這個環境被webpack編譯過,可以寫jsx,導入圖片
7、Umi的插件
(1)plugin-access,權限管理
(2)plugin-analytics,統計管理
(3)plugin-antd,整合 antd UI 組件
(4)plugin-initial-state,初始化數據管理
(5)plugin-layout,配置啟用 ant-design-pro 的布局
(6)plugin-locale,國際化能力
(7)plugin-model,基於 hooks 的簡易數據流
(8)plugin-request,基於 umi-request 和 umi-hooks 的請求方案
8、Umi其它
(1)配置:開發配置和(瀏覽器)運行配置
(2)路由:配置路由和約定式路由
(3)插件:id和key,每個插件都會對應一個id和一個key,id是路徑的簡寫,key是進一步簡化后用於配置的唯一值。

九、前端路由:url有變化,但不向后台發送請求,
1、它的作用是 
(1)記錄當前頁面的狀態; 
(2)可以使用瀏覽器的前進后退功能; 
2、hash模式幫我們實現這兩個功能,因為它能做到: 
(1)改變url且不讓瀏覽器向服務器發出請求; 
(2)監測 url 的變化; 
(3)截獲 url 地址,並解析出需要的信息來匹配路由規則。 
3、history 模式改變 url 的方式會導致瀏覽器向服務器發送請求。
4、react前端路由觸發條件
(1)<Link to={item.url}>{item.location}</Link>2)browserHistory.push('/aaa')

暫時留存
四、React組件生命周期
1、ES5寫法
ES5寫法之實例化時期
(1)propTypes = {}; getDefaultProps(){return{}};
(2)getInitialState(){return{}};
(3)componentWillMount//執行setState會合並到初始化狀態中;獲取從屬性生成的狀態
-----執行到這里,生命狀態會被重置為null
(4)render//執行setState會發起updateComponent導致-死循環5)componentDidMount//執行setState會導致更新;這是發起異步請求去API獲取數據的絕佳時期
ES5寫法之存在期
(1)componentWillReceiveProps//執行setState會合並到狀態中;
-----執行到這里,生命狀態會被重置為null
(2)shouldComponentUpdate//執行setState會發起updateComponent導致-死循環3)componentWillUpdate//執行setState會發起updateComponent導致-死循環4)render//執行setState會發起updateComponent導致-死循環5)componentDidUpdate//可以有條件地執行setState
ES5寫法之銷毀時期
(1)componentWillUnmount//等待頁面卸載,改變state沒意義。
2、ES6寫法(舊,React v16.3-)
ES6寫法之實例化時期
(1static propTypes = {}; static defaultProps = {}; 
(2)constructor
(3)componentWillMount//執行setState會合並到初始化狀態中;獲取從屬性生成的狀態
-----執行到這里,生命狀態會被重置為null
(4)render//執行setState會發起updateComponent導致-死循環5)componentDidMount//執行setState會導致更新;這是發起異步請求去API獲取數據的絕佳時期
ES6寫法之存在期
(1)componentWillReceiveProps//執行setState會合並到狀態中;----將有變動
-----執行到這里,生命狀態會被重置為null
(2)shouldComponentUpdate//執行setState會發起updateComponent導致-死循環3)componentWillUpdate//執行setState會發起updateComponent導致-死循環4)render//執行setState會發起updateComponent導致-死循環5)componentDidUpdate//可以有條件地執行setState
ES6寫法之銷毀時期
(1)componentWillUnmount//等待頁面卸載,改變state沒意義。
3、ES6寫法(新,React v16.4+)
ES6寫法之實例化時期
(1static propTypes = {}; static defaultProps = {}; 
(2)constructor
(3static getDerivedStateFromProps//執行setState會合並到初始化狀態中;獲取從屬性生成的狀態
-----執行到這里,生命狀態會被重置為null
(4)render//執行setState會發起updateComponent導致-死循環5)componentDidMount//執行setState會導致更新;這是發起異步請求去API獲取數據的絕佳時期
ES6寫法之存在期
(1static getDerivedStateFromProps//執行setState會合並到狀態中;----已有變動
-----執行到這里,生命狀態會被重置為null
(2)shouldComponentUpdate//執行setState會發起updateComponent導致-死循環
//此處沒有componentWillUpdate3)render//執行setState會發起updateComponent導致-死循環
//下(4)為新增4)getSnapshotBeforeUpdate//執行setState會發起updateComponent導致-死循環5)componentDidUpdate//可以有條件地執行setState
銷毀時期
(1)componentWillUnmount//等待頁面卸載,改變state沒意義。
另外====1)getDerivedStateFromProps//返回一個對象來更新state,如果返回 null 則不更新任何內容。
 
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM