初識(shí)react.js

安裝

npm i react react-dom
  • react包是核心, 提供創(chuàng)建元素, 組件等功能。
  • react-dom包提供DOM相關(guān)功能。

坑點(diǎn): 小伙伴再直接安裝時(shí)是不會(huì)生成node_modules, 需要 npm init -y進(jìn)行初始化生成package.json文件, 在進(jìn)行安裝就可以了

導(dǎo)入

  • 引入react和react-dom的兩個(gè)文件
<script src="./node_modules/react/umd/react.development.js"></script>
<script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
  • 創(chuàng)建React元素
    // 創(chuàng)建元素節(jié)點(diǎn)
    // 1. 元素名稱
    // 2. 元素屬性 傳對(duì)象
    // 3. 元素內(nèi)容
    let title = React.createElement('li', null, 'hellow react');
  • 渲染到頁(yè)面
     // 1.要渲染的元素
     // 2.要渲染到那個(gè)元素里面 
     ReactDOM.render(title, document.querySelector('#root'));

安裝腳手架

  • 初始化項(xiàng)目
npx create-react-app 項(xiàng)目名
  • npx目的:提升包內(nèi)提供的命令行工具的使用體驗(yàn)
  • 啟動(dòng)項(xiàng)目 npm start

JSX的使用

產(chǎn)生原因

由于通過(guò)createElement()方法創(chuàng)建的React元素有一些問(wèn)題, 代碼比較繁瑣,結(jié)構(gòu)不直觀,無(wú)法一眼看出描述的結(jié)構(gòu),不優(yōu)雅,用戶體驗(yàn)不好。

概述

JSX是JavaScript XML 的簡(jiǎn)寫(xiě),表示在JavaScript代碼中編寫(xiě)HTML格式的代碼
優(yōu)勢(shì):聲明式語(yǔ)法更加直觀, 與HTML結(jié)構(gòu)相同,降低了學(xué)習(xí)成本,提升開(kāi)發(fā)效率。

為什么在腳手架中可以使用JSX語(yǔ)法
  • JSX 不是標(biāo)準(zhǔn)的ECMAScript語(yǔ)法,它是ECMAScript的語(yǔ)法拓展
  • 需要使用babel編譯處理后,才能在瀏覽器環(huán)境中使用
  • create-react-app腳手架中已經(jīng)默認(rèn)有該配置,無(wú)需手動(dòng)配置
  • 編譯JSX語(yǔ)法的包: @bable/preset-react
注意點(diǎn)
  • React元素的屬性名使用駝峰命名法
  • 特殊屬性名:class -> className,for -> htmlFor,tabindex -> tabIndex
  • 如果沒(méi)有子節(jié)點(diǎn)的React元素可以用 /> 來(lái)結(jié)束
  • 推薦:使用 小括號(hào)包裹JSX,從而避免JS中自動(dòng)插入分號(hào)報(bào)錯(cuò)

JSX語(yǔ)法

條件渲染
let isLoading = true
let loading = ()=>{
    if(isLoading){
        return <div>Loading...</div>
    }
    return <div>加載完成</div>
}
列表渲染
let arr = [{
  id: 1,
  name: '肖'
}, {
  id: 2,
  name: '小'
}, {
  id: 3,
  name: '笑'
}]
let arrMap = () => {
  return (
    <ul>
      {arr.map(item => <li key={item.id}>{item.name}</li>)}
    </ul>
  )
}
樣式處理

在style里面通過(guò)對(duì)象的方式傳遞數(shù)據(jù)

let arrMap = () => {
  return (
    <ul>
      {arr.map(item => <li key={item.key} style={{ "color": "red", "backgroundColor": "pink" }}> {item.name} </li>)}
    </ul>
  )
}

不過(guò)這種方式比較麻煩,不方便閱讀,而且還會(huì)導(dǎo)致代碼比較繁瑣,權(quán)重性高

類(lèi)名-className

創(chuàng)建css文件編寫(xiě)樣式代碼

.container {
    text-align: center
}

在js中進(jìn)行引入,然后設(shè)置類(lèi)名即可

import './css/index.css'

<li className='container' key={item.id} style={{'color': 'red',"backgroundColor": 'pink'}}>{item.name}</li>

React組件

  • 組件是React的主要,使用React就是在用組件
  • 組件表示頁(yè)面中的部分功能
  • 組合多個(gè)組件實(shí)現(xiàn)完整的頁(yè)面功能
  • 特點(diǎn):可復(fù)用、獨(dú)立、可組合

組件的創(chuàng)建方式

函數(shù)創(chuàng)建組件
  • 函數(shù)組件:使用JS的函數(shù)創(chuàng)建組件
  • 約定1:函數(shù)名稱必須以大寫(xiě)字母開(kāi)頭
  • 約定2:函數(shù)組件必須有返回值,表示該組件的結(jié)構(gòu)
  • 如果返回值為null,表示不渲染任何內(nèi)容
function Hello() {
  return <div>這是第一個(gè)函數(shù)組件</div>
}
類(lèi)組件
  • 使用ES6語(yǔ)法的class創(chuàng)建的組件
  • 約定1:類(lèi)名稱也必須要大寫(xiě)字母開(kāi)頭
  • 約定2:類(lèi)組件應(yīng)該繼承React.Component父類(lèi),從而可以使用父類(lèi)中提供的方法或者屬性
  • 約定3:類(lèi)組件必須提供 render 方法
  • 約定4:render方法中必須要有return返回值
class Hello extends React.Component {
  render() {
    return (
      <div>這是第一個(gè)類(lèi)組件</div>
    )
  }
}

React的事件處理

  • React事件綁定語(yǔ)法與DOM事件語(yǔ)法相似
  • 語(yǔ)法:on+事件名稱=事件處理函數(shù),比如 onClick = function(){}
  • 注意:React事件采用駝峰命名法
class Hello extends React.Component {
  clickHandle(e) {
    console.log('肖帥哥點(diǎn)我了');
  }
  render() {
    return (
      <div onClick={this.clickHandle}>這是第一個(gè)類(lèi)組件</div>
    )
  }
}

事件對(duì)象

  • 可以通過(guò)事件處理函數(shù)的參數(shù)獲取到事件對(duì)象
  • React中的事件對(duì)象叫做:合成事件
  • 合成事件:兼容所有瀏覽器,無(wú)需擔(dān)心跨瀏覽器兼容問(wèn)題
  • 除兼容所有瀏覽器外,它還擁有和瀏覽器原生事件相同的接口,包括 stopPropagation()preventDefault()
  • 如果你想獲取到原生事件對(duì)象,可以通過(guò) nativeEvent 屬性來(lái)進(jìn)行獲取
class Hello extends React.Component {
  clickHandle(e) {
    console.log(e.nativeEvent);
  }
  render() {
    return (
      <div><button onClick={this.clickHandle}>這是第一個(gè)類(lèi)組件</button></div>
    )
  }
}

有狀態(tài)和無(wú)狀態(tài)組件

  • 函數(shù)組件又叫做 無(wú)狀態(tài)組件,類(lèi)組件又叫做 有狀態(tài)組件
  • 狀態(tài)(state) 即數(shù)據(jù)
  • 函數(shù)組件沒(méi)有自己的狀態(tài),只負(fù)責(zé)數(shù)據(jù)展示
  • 類(lèi)組件有自己的狀態(tài),負(fù)責(zé)更新UI,讓頁(yè)面動(dòng)起來(lái)

State和SetState

state基本使用
  • 狀態(tài)(state)即數(shù)據(jù),是組件內(nèi)部的私有數(shù)據(jù),只能在組件內(nèi)部使用
  • state的值是對(duì)象,表示一個(gè)組件中可以有多個(gè)數(shù)據(jù)
  • 通過(guò)this.state來(lái)獲取狀態(tài)
export default class extends React.Component {
    constructor(){
        super()

        // 第一種初始化方式
        this.state = {
            count : 0
        }
    }
    // 第二種初始化方式
    state = {
        count:1
    }
    render(){
        return (
            <div>計(jì)數(shù)器 :{this.state.count}</div>
        )
    }
}
setState() 修改狀態(tài)
  • 狀態(tài)是可變的
  • 語(yǔ)法:this.setState({要修改的數(shù)據(jù)})
  • 注意:不要直接修改state中的值,這是錯(cuò)誤的
  • setState() 作用:1.修改 state 2.更新UI

抽取事件處理函數(shù)

  • 當(dāng)我們把上面代碼的事件處理程序抽取出來(lái)后,會(huì)報(bào)錯(cuò),找不到this


    image.png
原因

在ES6箭頭函數(shù)中知道,箭頭函數(shù)本身是沒(méi)有this的,它只會(huì)去向外一層去尋找。
在JSX中寫(xiě)的事件處理函數(shù)可以找到this,因?yàn)橥鈱邮莚ender方法,在render方法里面的this剛好指向的是當(dāng)前實(shí)例對(duì)象。

事件綁定this指向

箭頭函數(shù)
  • 利用箭頭函數(shù)自身不綁定this的特點(diǎn)
class App extends Component {
  state = {
    count: 1
  }
  add() {
    this.setState({
      count: this.state.count + 1
    })
  }
  render() {
    return (
      <div>
        <div>計(jì)數(shù)器 :{this.state.count}</div>
        <button onClick={() => this.add()}>+1</button>
      </div>
    )
  }
}
利用bind方法

利用原型bind方法是可以更改函數(shù)里面this的指向的,所以我們可以在構(gòu)造中調(diào)用bind方法,然后把返回的值賦值給我們的函數(shù)即可

class App extends Component {
  constructor() {
    super()
    this.state = {
      count: 1
    }
    // 通過(guò)bind方法改變了當(dāng)前函數(shù)中this的指向
    this.add = this.add.bind(this);
  }
  add() {
    this.setState({
      count: this.state.count + 1
    })
  }
  render() {
    return (
      <div>
        <div>計(jì)數(shù)器 :{this.state.count}</div>
        <button onClick={this.add}>+1</button>
      </div>
    )
  }
}

class的實(shí)例方法

  • 利用箭頭函數(shù)形式的class實(shí)例方法
  // 事件處理程序
  add = () => {
    console.log('事件處理程序中的this:', this)
    this.setState({
      count: this.state.count + 1
    })
  }

表單處理

受控組件
  • HTML中的表單元素是可輸入的,也就是有自己的可變狀態(tài)
  • 而React中可變狀態(tài)通常保存在state中,并且只能通過(guò)setState() 方法來(lái)修改
  • React講state與表單元素值value綁定在一起,有state的值來(lái)控制表單元素的值
  • 受控組件:值受到react控制的表單元素


    image.png
class App extends Component {
  state = {
    txt: ''
  }
  txtChanget = (e) => {
    this.setState({
      txt: e.target.value
    })
  }
  render() {
    return (
      <div>
        <input type="text" value={this.state.txt} onChange={this.txtChanget} />
      </div>
    )
  }
}
多表單元素優(yōu)化
  • 問(wèn)題:每個(gè)表單元素都有一個(gè)單獨(dú)的事件處理函數(shù),這樣太繁瑣
  • 優(yōu)化:使用一個(gè)事件處理程序同時(shí)處理多個(gè)表單元素
class App extends Component {
  state = {
    txt: '',
    isChecked: ''
  }
  txtChanget = ({ target }) => {
    let value = target.type == 'checkbox' ? target.checked : target.value;
    this.setState({
      [target.name]: value
    })
  }
  render() {
    console.log(this.state.txt, this.state.isChecked)
    return (
      <div>
        <input type="text" value={this.state.txt} onChange={this.txtChanget} name="txt" />
        <input type="checkbox" value={this.state.isChecked} name="isChecked" onChange={this.txtChanget} />
      </div>
    )
  }
}

非受控組件

  • 說(shuō)明:借助于ref,使用元素DOM方式獲取表單元素值
  • ref的作用:獲取DOM或者組件
class App extends Component {
  txtRef = React.createRef();
  getTxt = () => {
    console.log(this.txtRef.current.value)
  }
  render() {
    return (
      <div>
        <input type="text" ref={this.txtRef} />
        <button onClick={this.getTxt}></button>
      </div>
    )
  }
}

React組件進(jìn)階

組件通訊

組件是獨(dú)立且封閉的單元,默認(rèn)情況下,只能使用組件自己的數(shù)據(jù)。在組件化過(guò)程中,我們將一個(gè)完整的功能拆分成多個(gè)組件,以更好的完成整個(gè)應(yīng)用的功能。而在這個(gè)過(guò)程中,多個(gè)組件之間不可避免的要共享某些數(shù)據(jù)。為了實(shí)現(xiàn)這些功能,就需要打破組件的獨(dú)立封閉性,讓其與外界溝通,這個(gè)過(guò)程就是組件通訊

組件的props
  • 組件時(shí)封閉的,要接受外部數(shù)據(jù)應(yīng)該通過(guò)props來(lái)實(shí)現(xiàn)
  • props的作用:接收傳遞給組件的數(shù)據(jù)
  • 傳遞數(shù)據(jù):給組件標(biāo)簽添加屬性
<Hello name="肖"></Hello>

接收數(shù)據(jù):函數(shù)組件通過(guò) 參數(shù) props接收數(shù)據(jù),類(lèi)組件通過(guò) this.props接收數(shù)據(jù)

  • 函數(shù)組件獲取
const Hello = (props) => {
  return <div>{props.name}</div>
}
  • 類(lèi)組件獲取
class Hello extends React.Component {
  render() {
    return (
      <div>{this.props.name}</div>
    )
  }
}
特點(diǎn)
  • 可以給組件傳遞任意類(lèi)型的數(shù)據(jù)
  • props是只讀屬性,不能對(duì)值進(jìn)行修改
  • 注意:使用類(lèi)組件時(shí),如果寫(xiě)了構(gòu)造函數(shù),應(yīng)該將props傳遞給super(),否則,無(wú)法在構(gòu)造函數(shù)中獲取到props,其他的地方是可以拿到的
class Hello extends React.Component {
  constructor(props) {
    super(props)
  }
  render() {
    return (
      <div>{this.props.name}</div>
    )
  }
}

組件通訊的三種方式

父組件傳遞數(shù)據(jù)給子組件
  • 父組件提供要傳遞的state數(shù)據(jù)
  • 給子組件標(biāo)簽添加屬性,值為state中的數(shù)據(jù)
  • 子組件中通過(guò)props接收父組件中傳遞的數(shù)據(jù)
子組件傳遞數(shù)據(jù)給父組件
// 子組件
class Hello extends React.Component {
  state = {
    name: '肖'
  }
  goApp = () => {
    this.props.getMsg(this.state.name);
  }
  render() {
    return (
      <div>
        <button onClick={this.goApp}></button>
      </div>
    )
  }
}

// 父組件
class App extends Component {
  getChildMsg = (msg) => {
    console.log(msg);
  }
  render() {
    return (
      <div>
        <Hello getMsg={this.getChildMsg}></Hello>
      </div>
    )
  }
}
兄弟組件傳遞
  • 將共享狀態(tài)(數(shù)據(jù))提升到最近的公共父組件中,由公共父組件管理這個(gè)狀態(tài)
  • 這個(gè)稱為狀態(tài)提升
  • 公共父組件職責(zé):1. 提供共享狀態(tài) 2.提供操作共享狀態(tài)的方法
  • 要通訊的子組件只需要通過(guò)props接收狀態(tài)或操作狀態(tài)的方法
// 兄弟組件
class Child1 extends React.Component {
  render() {
    return (
      <h1>計(jì)數(shù)器:{this.props.count}</h1>
    )
  }
}
class Child2 extends React.Component {
  child2Add = () => {
    this.props.add(1)
  }
  render() {
    return (
      <button onClick={this.child2Add}>+1</button>
    )
  }
}

// 父組件
class App extends Component {
  state = {
    count: 0
  }
  add = (count) => {
    this.setState({
      count: this.state.count + count
    })
  }
  render() {
    return (
      <div>
        <Child1 count={this.state.count}></Child1>
        <Child2 add={this.add}></Child2>
      </div>
    )
  }
}

Context

如果出現(xiàn)層級(jí)比較多的情況下(例如:爺爺傳遞數(shù)據(jù)給孫子),我們會(huì)使用Context來(lái)進(jìn)行傳遞
作用: 跨組件傳遞數(shù)據(jù)

const { Provider, Consumer } = React.createContext();
class Child extends React.Component {
  render() {
    return (
      <div>子組件
        <Consumer>
          {data => <span>{data}</span>}
        </Consumer>
      </div>
    )
  }
}
// 父組件
class App extends Component {
  render() {
    return (
      <Provider value="pink">
        <div>
          <Child></Child>
        </div>
      </Provider>
    )
  }
}

props效驗(yàn)

  • 對(duì)于組件來(lái)說(shuō),props是外來(lái)的,無(wú)法保證組件使用者傳入什么格式的數(shù)據(jù),簡(jiǎn)單來(lái)說(shuō)就是組件調(diào)用者可能不知道組件封裝著需要什么樣的數(shù)據(jù)
  • 如果傳入的數(shù)據(jù)不對(duì),可能會(huì)導(dǎo)致報(bào)錯(cuò)
  • 關(guān)鍵問(wèn)題:組件的使用者不知道需要傳遞什么樣的數(shù)據(jù)
  • props校驗(yàn):允許在創(chuàng)建組件的時(shí)候,指定props的類(lèi)型、格式等
安裝
  • 安裝包 prop-types
  • 導(dǎo)入prop-types 包
  • 使用組件名.propTypes={} 來(lái)給組件的props添加校驗(yàn)規(guī)則
  • 校驗(yàn)規(guī)則通過(guò)PropTypes對(duì)象來(lái)指定
npm install --save prop-types
import PropTypes from 'prop-types'
// 子組件
class Child extends React.Component {
  render() {
    return (
      <div>
        {this.props.name}
      </div>
    )
  }
}
// 不要寫(xiě)在前面,因?yàn)樵诔跏蓟笆菦](méi)有Child這個(gè)組件的
Child.propTypes = {
  name: PropTypes.string
}
//父組件
class App extends React.Component {
  render() {
    return (
      <div>
        <Child name="xin"></Child>
      </div>
    )
  }
}
常規(guī)約束規(guī)則
  • 創(chuàng)建的類(lèi)型: array、bool、func、number、object、string
  • React元素類(lèi)型:element
  • 必填項(xiàng):isRequired
  • 特定結(jié)構(gòu)的對(duì)象: shape({})
  • 更多的約束規(guī)則
    image.png

props的默認(rèn)值

import PropTypes from 'prop-types'
// 子組件
class Child extends React.Component {
  render() {
    return (
      <div>
        {this.props.name}
      </div>
    )
  }
}
// 不要寫(xiě)在前面,因?yàn)樵诔跏蓟笆菦](méi)有Child這個(gè)組件的
Child.defaultProps = {
  name: '哈哈'
}
//父組件
class App extends React.Component {
  render() {
    return (
      <div>
        <Child></Child>
      </div>
    )
  }
}
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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