React的基礎(chǔ)入門學(xué)習(xí)

1、Hello,Word

React干嘛的,有什么用可以去官網(wǎng)瞧瞧

安裝

react核心庫(kù)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
react操作dom的庫(kù)
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
babel轉(zhuǎn)義jsx語(yǔ)法
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

提供根節(jié)點(diǎn)

<div id="app"></div>

編寫JSX

babel語(yǔ)法
<script type="text/babel">
//創(chuàng)建虛擬dom
const VDOM = <h1>Hello,Word</h1>
ReactDOM.render(VDOM,document.getElementById('app'))
</script>
image.png

2、JSX的語(yǔ)法規(guī)則

2-1、虛擬dom是什么類型的?

const VDOM = <h1>Hello,Word</h1>
console.log(VDOM instanceof Object)
console.log(VDOM)
image.png

其實(shí)JSX中虛擬dom就是個(gè)json對(duì)象,當(dāng)然原生的dom節(jié)點(diǎn)其實(shí)也是對(duì)象

image.png

只不過(guò)相對(duì)于原生來(lái)說(shuō)少了很多屬性。

2-2、虛擬DOM使用變量

var hId = 't-h1';
var Txt = '變量文本';
var style = {color:'white',backgroundColor:'orange'}
const VDOM = (
    <h1 id={hId} style={style}>{Txt}</h1>
)
ReactDOM.render(VDOM,document.getElementById('app'))
image.png

注意:1、在虛擬dom中定義類名需要使用className
2、使用內(nèi)聯(lián)樣式需要使用花括號(hào)把對(duì)象包裹起來(lái)
3、定義虛擬DOM不需要使用單引號(hào),如果使用就會(huì)變成字符串了
4、虛擬DOM只能有一個(gè)根節(jié)點(diǎn)
5、虛擬DOM的節(jié)點(diǎn)定義規(guī)則:
5-1、首字母小寫,如果為html中的同名標(biāo)簽,則渲染為同名元素,如果不是則直接渲染改標(biāo)簽,且會(huì)報(bào)錯(cuò)
5-2、首字母大寫,則為React中的自定義組件

3、React組件

3-1、函數(shù)式組件

//注意這里需要大寫首字母原因請(qǐng)看jsx語(yǔ)法規(guī)則
const data = ['Angulay', 'React', 'Vue'];
function Demo(abc) {
    console.log(this)
    return (
        <div>
            <h1>自定義組件</h1>
            <ul>
                {data.map(item => <li key={item}>{item}</li>)}
            </ul>
        </div>
    )
}

ReactDOM.render(<Demo />, document.getElementById('app'))

注意此處的函數(shù)中this并不是window,也不是React實(shí)例,因?yàn)樵赽abel中轉(zhuǎn)義會(huì)添加嚴(yán)格模式use strict嚴(yán)格模式下,禁止函數(shù)內(nèi)this指向window

3-2、類式組件

class HelloMessage extends React.Component{
    render(){
        return <h1>類式組件的定義</h1>
    }
}
ReactDOM.render(<HelloMessage />,document.getElementById('app'))

類式組件定義規(guī)則:1、必須繼承自React.Component這個(gè)類
2、必須含有一個(gè)render方法,且必須有一個(gè)返回值
3、類中可以不用constructor方法

當(dāng)ReactDOM.render一個(gè)類組件發(fā)生了什么?

1、React解析組件標(biāo)簽,找到了自定義組件。
2、發(fā)現(xiàn)自定義組件是類定義,隨后new出一個(gè)實(shí)例出來(lái),并且調(diào)用原形上render方法
3、講原形上render返回的虛擬dom返回在真是dom上

4、狀態(tài) State

我們先看下類式組件的this到底有些什么東西?

class MyWeatch extends React.Component {
    render() {
        console.log(this);
        return (
            <div className="test">
                Hello,Word
            </div>
        )
    }
}
ReactDOM.render(<MyWeatch />, document.getElementById('app'))
image.png

state已被掛在在組件的實(shí)例對(duì)象上

4-1、案例使用state進(jìn)行操作

class MyWeacth extends React.Component{
  constructor(props){
    super(props)
    this.state = {
      isHot:false
    }
  }
  render(){
    const {isHot}  = this.state;
    return <h1>今天天氣很{isHot?'炎熱':'涼爽'}</h1>
  }
}

注意:你必須使用構(gòu)造器constructor,并且需要接受

4-2、使用事件處理調(diào)用函數(shù)

class Weatch extends React.Component{
  constructor(props){
    super(props)
    this.state = {
      isHot:false
    }
  }
  render(){
    const {isHot}  = this.state;
    return <h1 onClick={this.handleHot.bind(this)}>今天天氣很{isHot?'炎熱':'涼爽'}</h1>
  }
  handleHot(){
    console.log(this.state.isHot)
  }
}

注意:1、在React中監(jiān)聽事件我們使用原生的方法在標(biāo)簽上寫入方法,并且是駝峰命名
2、如果你直接賦值原型函數(shù),則該函數(shù)的thisundefined,所以必須是使用bind處理this指向

4-3、改變State的值

根據(jù)上述例子我們會(huì)發(fā)現(xiàn)直接更改state.isHot的值,雖然他的值確實(shí)被改變了,但是最終視圖并沒有被改變!

、、、
 handleHot(){
    console.log(this.state.isHot) 你會(huì)發(fā)現(xiàn)值確實(shí)被改變了
    this.state.isHot = !this.state.isHot
    
  }

在React中你不可以直接改變狀態(tài)的值,你必須使用父類原型中的setState方法進(jìn)行改變數(shù)據(jù)。

handleStatus() {
    this.setState({
        isHot: !this.state.isHot
    })
}

已經(jīng)實(shí)現(xiàn)了功能,視圖也更新了

4-4、疑問(wèn),setState是替換了state的整個(gè)對(duì)象,還是對(duì)象中的具體屬性?

class HelloMessage extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            isHot: false,
            isTxt: '測(cè)試文字'
        }
    }

    render() {
        const { isHot, isTxt } = this.state
        return <h1 onClick={this.handleStatus.bind(this)}>測(cè)試啊{isHot ? '可以' : 'no no'},案例:{isTxt}</h1>
    }

    handleStatus() {
        this.setState({
            isHot: !this.state.isHot
        })
      console.log(this.state)
    }
}
image.png

會(huì)發(fā)現(xiàn)setState只是改變了具體的某個(gè)屬性,并沒有對(duì)整個(gè)state的值進(jìn)行賦值,它的操作類似于Object.assign(this.state,arguments)

4-5、疑問(wèn)?對(duì)state進(jìn)行更新,構(gòu)造器constructor、render、依賴的事件函數(shù)他們會(huì)被調(diào)用么?調(diào)用多少次?

用代碼說(shuō)話

class HelloMessage extends React.Component {
    constructor(props) {
        console.log('constructor');
        super(props)
        this.state = {
            isHot: false,
            isTxt: '測(cè)試文字'
        }
    }

    render() {
        console.log('render');
        const { isHot, isTxt } = this.state
        return <h1 onClick={this.handleStatus.bind(this)}>測(cè)試啊{isHot ? '可以' : 'no no'},案例:{isTxt}</h1>
    }

    handleStatus() {
        console.log('handleStatus');
        this.setState({
            isHot: !this.state.isHot
        })
    }
}

我們點(diǎn)擊h1標(biāo)簽看看怎么打印的?

image.png

通過(guò)這次小案例 我們就知道了:
1、構(gòu)造器constructor只會(huì)在自定義組件第一次綁定的時(shí)候才會(huì)調(diào)用一次,除非你在多個(gè)地方使用了該自定義組件
2、render函數(shù)會(huì)在調(diào)用setState/props改變,父組件更新,時(shí)會(huì)調(diào)用
3、事件處理函數(shù)當(dāng)然只會(huì)在你每次觸發(fā)的時(shí)候在調(diào)用。

4-6、精簡(jiǎn)寫法

首先我們先復(fù)習(xí)下普通的類的寫法

class Person{
  name="人";
  age = 18;
  constructor(){
    this.eye = 2;
  }
  handle = ()=>{
    console.log(this)
  }
  handleProto(){
    
  }
}

請(qǐng)問(wèn)下?name、age、handle函數(shù)他們被放在哪了?

image.png

他們被放在了實(shí)例的自身屬性上??!不是原型上,所以React的精簡(jiǎn)寫法來(lái)了!

class HelloMessage extends React.Component {
    state = { isHot: false, }

    render() {
        const { isHot } = this.state
        return <h1 onClick={this.handleStatus}>測(cè)試啊{isHot?'1':'2'}</h1>
    }

    handleStatus = () => {
        this.setState({
            isHot: !this.state.isHot
        })
    }
}

5、Prop傳值

想象一個(gè)場(chǎng)景,如果我們自己封裝了一個(gè)自定義組件,但是組件里面的用到的數(shù)據(jù)有些是需要用戶傳進(jìn)來(lái)的,但是不可能讓用戶自己修改里面的代碼吧?所以我們引入一個(gè)概念Props

class HelloMessage extends React.Component {
    render() {
        const { name, age } = this.props;
        return <h1>姓名:{name},年齡:{age}</h1>
    }
}

ReactDOM.render(<HelloMessage name="tom" age="18" />, document.getElementById('app'))

5-1、更簡(jiǎn)便的傳值

利用展開運(yùn)算符...進(jìn)行解構(gòu)對(duì)象,我們知道大部分的數(shù)據(jù)我們都是后臺(tái)傳過(guò)來(lái)的,所以我們可以在外部定義一個(gè)json對(duì)象模擬數(shù)據(jù)

class HelloMessage extends React.Component {
    render() {
        const { name, age } = this.props;
        return <h1>姓名:{name},年齡:{age}</h1>
    }
}
let p = { name: 'tom', age: 18 }
ReactDOM.render(<HelloMessage {...p} />, document.getElementById('app'))

5-2、Props的規(guī)則驗(yàn)證

例如上述案例,我們可以知道,這用戶傳值隨心所欲,如我不傳姓名,或者姓名我傳數(shù)字怎么辦?所以我們需要限制他的傳值類型


image.png

在老版本上React對(duì)象上掛載了一個(gè)PropTypes對(duì)象,不過(guò)現(xiàn)在已被移除了,移到一個(gè)單獨(dú)的包中

我們引入csdn單獨(dú)的PropTypes的包

<script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>

我們看下PropTypes身上到底有些什么東西

console.log(PropTypes)
PropTypes身上的屬性

5-2-1、PropTypes的使用規(guī)則

你需要在自定義組件的類名添加一個(gè)靜態(tài)屬性propTypes注意是小寫的p

class MyComponent extends React.Component{
  static propTypes = {
    name:PropType.string,
    age:PropType.number
  }
}

這是基本的驗(yàn)證規(guī)則
props屬性必傳isRequired

static propTypes = {
  name:PropType.string.isRequired, //必傳
  age:PropType.number
}

props之屬性默認(rèn)值
你需要給自定義組件添加靜態(tài)的defaultProps屬性

static defaultProps = {
  name:'Tom'
}

props是只讀的,單向數(shù)據(jù)流

5-3、如果使用構(gòu)造器constructor,那么我不接收pops,會(huì)怎么樣

官方案例
、、、
{
  constructor(props){
    super(props)
    console.log(this.props)
  }
}
//不接收props
{
  constructor(){
    super()
    console.log(this.props)//undefined
  }
}

如果你需要在構(gòu)造器constructor中操作props那么你就需要把props傳給分類

6、Refs

獲取原生dom對(duì)象,和vue中的用法是一致的,在虛擬節(jié)點(diǎn)上添加ref屬性

6-1、字符串設(shè)置refs 即將廢棄

為什么會(huì)被廢棄?過(guò)時(shí) API:String 類型的 Refs

handleClick = ()=>{
  console.log(this.refs)
}
render(){
  return <h1 ref="ish" onClick={this.handleClick}>Refs使用</h1>
}

6-2、回調(diào)形式refs

也就是在 ref賦值的時(shí)候?qū)懭胍粋€(gè)函數(shù)

6-2-1、內(nèi)聯(lián)回調(diào)函數(shù)

render(){
  return <h1 ref={curr=>this.ish = curr}>Refs的使用</h1>
}

但是注意的是:
1、內(nèi)聯(lián)回調(diào)函數(shù)不會(huì)往refs對(duì)象中添加屬性,在這里你相當(dāng)于在實(shí)例身上添加了一個(gè)ish的屬性
2、內(nèi)聯(lián)回調(diào)形式的refs會(huì)在組件更新狀態(tài)的時(shí)候調(diào)用兩次,一次的參數(shù)值為null第二次才是真正的節(jié)點(diǎn)

6-2-2、賦值一個(gè)函數(shù)的形式

saveH = (curr)=>{
  this.ish = curr
}
render(){
  return <h1 ref={this.saveH}>Refs的使用</h1>
}

這個(gè)可以避免內(nèi)聯(lián)回調(diào)的兩個(gè)缺點(diǎn),但是,他又會(huì)增加組件實(shí)例上的屬性過(guò)多且很雜。所以一般我們還是采用內(nèi)聯(lián)形式的方式

6-3、使用最新的API createRef

$refs = React.createRef()
handleClick = ()=>{
    console.log(this.$refs);
}
render() {

    return <div ref={this.$refs} onClick={this.handleClick}>

        側(cè)是是是
    </div>
}

遺憾是使用createRef創(chuàng)建出來(lái)的屬性 只能是"專人專用",也就是說(shuō)如果還有第二個(gè)節(jié)點(diǎn)需要使用ref那么又得重新使用createRef創(chuàng)建一個(gè)新的屬性出來(lái)

7、高階函數(shù)/函數(shù)柯里化

什么是高階函數(shù)?
1、如果一個(gè)函數(shù)的參數(shù)是一個(gè)函數(shù)那么該函數(shù)就是高階函數(shù)
2、如果一個(gè)函數(shù)返回了一個(gè)函數(shù),那么該函數(shù)也是高階函數(shù)

閉包、Promise、setTimeOut、Array.map、、、等等

7-1、在React中使用高階函數(shù)

想象一個(gè)場(chǎng)景,如果一個(gè)虛擬dom綁定的事件做的事都幾乎一樣,那么我們沒必要定義多個(gè)函數(shù),排除內(nèi)聯(lián)函數(shù)(箭頭函數(shù))

handleClick = (type)=>{
  ****
console.log(type)
switch(type){、、、}
}
render(){
  return (
    <div>
      <span onClick={this.handleClick('type1')}>測(cè)試1</span>
      <span onClick={this.handleClick('type2')}>測(cè)試2</span>
      <span onClick={this.handleClick('type3')}>測(cè)試3</span>
     </div>
  )
}

如果我們直接直接這樣,就相當(dāng)于在render的時(shí)候React自己幫我們調(diào)用了這個(gè)函數(shù),后面就不會(huì)響應(yīng)我們的點(diǎn)擊事件,解決辦法,返回一個(gè)函數(shù)

handleClick = (type)=>{
  return (event)=>{
    
  }
}
render(){
  return (
    <div>
      <span onClick={this.handleClick('type1')}>測(cè)試1</span>
      <span onClick={this.handleClick('type2')}>測(cè)試2</span>
      <span onClick={this.handleClick('type3')}>測(cè)試3</span>
     </div>
  )
}

7-2、函數(shù)柯里化

含義:通過(guò)函數(shù)調(diào)用繼續(xù)返回的函數(shù)的方式,實(shí)現(xiàn)多次接收參數(shù)最后統(tǒng)一處理的函數(shù)編碼方式

不用柯里化求三個(gè)值得和
function sum(a,b,c){return a+b+c}
柯里化
function sum(a){
   return (b)=>{
    return (c)=>{
       return a+b+c
     }
   }
}

8、React生命周期(舊)

image.png

1、組件掛載前=>componentWillMount
2、組件掛載后=>componentDidMount
3、組件卸載前=>componentWillUnmount
4、組件更新前=>componentWillUpdate
5、組件更新后=>componentDidUpdate
6、組件更新閥門=>shouldComponentUpdate
7、父組件render后并改變了子組件props監(jiān)聽第二次變化=>componentWillReceiveProps

知識(shí)點(diǎn):
- 主動(dòng)卸載一個(gè)組件ReactDOM.unmountComponentAtNode(節(jié)點(diǎn))
- 在生命周期中你會(huì)發(fā)現(xiàn)帶有Will都是觸發(fā)前,帶有Did都是觸發(fā)完成后

8-1 最新生命周期

image.png

我們知道react是要經(jīng)歷三個(gè)階段掛載、更新、卸載

掛載:
constructor(初始化)
getDerivedStateFromProps
render
componentDidMount
更新:
getDerivedStateFromProps
shouldComponentUpdate
getSnapshotBeforeUpdate
componentDidUpdate
卸載
componentWillUnMount

9、React腳手架

10、React路由

React的路由:react-router(比較綜合可以給react native使用)、react-router-dom(web端)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 3. JSX JSX是對(duì)JavaScript語(yǔ)言的一個(gè)擴(kuò)展語(yǔ)法, 用于生產(chǎn)React“元素”,建議在描述UI的時(shí)候...
    pixels閱讀 2,979評(píng)論 0 24
  • It's a common pattern in React to wrap a component in an ...
    jplyue閱讀 3,407評(píng)論 0 2
  • 原教程內(nèi)容詳見精益 React 學(xué)習(xí)指南,這只是我在學(xué)習(xí)過(guò)程中的一些閱讀筆記,個(gè)人覺得該教程講解深入淺出,比目前大...
    leonaxiong閱讀 2,944評(píng)論 1 18

友情鏈接更多精彩內(nèi)容