日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从零开始的React学习(一)

發(fā)布時間:2024/1/18 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从零开始的React学习(一) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

React基礎(chǔ)

寫在前面:這是我學(xué)習(xí)B站黑馬React視頻前75p所作的筆記。
后續(xù)的學(xué)習(xí)也會整理出筆記,供自己之后翻閱,也希望能給你帶來一些幫助。

(1)概述

? 用于構(gòu)建用戶界面的JavaScript庫

(2)特點

  • 基于組件
  • 學(xué)習(xí)一次,隨處使用

(3)基本安裝與使用

  • 安裝命令

    npm i react react-dom
  • 使用

    // 1.導(dǎo)入react和react-dom文件 import React from 'react' import ReactDOM from 'react-dom'// 2.創(chuàng)建react元素 const title = React.createElement('h1', null, 'hello world!')// 3.渲染react元素 ReactDOM.render(title, document.getElementById('root'))
  • (4)腳手架安裝與使用

  • 意義

    • 腳手架是開發(fā)現(xiàn)代Web應(yīng)用的必備
    • 充分利用Webpack、Babel、ESLint等工具輔助項目開發(fā)
    • 零配置,無需手動配置繁瑣的工具即可使用
    • 關(guān)注業(yè)務(wù),而不是工具配置
  • 初始化

    npx create-react-app my-appnpx 是npm v5.2.0 引入的一條命令 目的是提升包內(nèi)提供的命令行工具的使用體驗; 原來需要先安裝腳手架包,再使用這個包中提供的命令;現(xiàn)在無需安裝腳手架包,可以直接使用這個包中提供的命令。
  • 使用

    同上。

    啟動命令 yarn start 或 npm start
  • (5)React Developer Tools 相關(guān)問題

    這是我個人遇到的一些相關(guān)問題:

  • 安裝:不能科學(xué)上網(wǎng)時chrome商店打不開,就度娘找找資源,下載然后拖到瀏覽器擴(kuò)展應(yīng)用里會自動安裝。
  • 不能動態(tài)顯示數(shù)據(jù):我的原因是自己在 component里的Hide components where…加了過濾,去掉過濾就好
  • 控制臺可能有警告(強(qiáng)迫癥難受):把瀏覽器的迅雷下載組件刪了,或者是把瀏覽器F12的setting下的Preferences里的 Enable JavaScript source maps 和 Enable CSS source maps取消勾選即可
  • 插件不可用:在擴(kuò)展應(yīng)用的React Developer Tools 的詳情里,打開 “允許訪問文件網(wǎng)址”
  • 一、基礎(chǔ)

    (1)JSX的基本使用

    ? 用React.createElement()繁瑣,不直觀,不優(yōu)雅。

    JSX簡介

    JSX是React的核心內(nèi)容。是JavaScript XML簡寫。優(yōu)勢是聲明式的語法,更加直觀,與HTML結(jié)構(gòu)相同,降低學(xué)習(xí)成本,提高開發(fā)效率。

    1.使用步驟
    /* 使用JSX創(chuàng)建React元素 */ const title = (<h1 className="title">hello JSX!<span>這是span</span></h1> ) // 渲染react元素 const root = document.getElementById('root') ReactDOM.render(title, root)

    為什么腳手架中可以使用JSX語法?

    • JSX不是標(biāo)準(zhǔn)的ECMAScript語法,是ECMAScript的語法擴(kuò)展

    • 需要使用babel編譯處理后才能在瀏覽器環(huán)境使用

    • create-react-app腳手架中已經(jīng)默認(rèn)有該配置,無需手動配置

    • 編譯JSX語法的包:@babel/preset-react

    2.注意點
    • React元素的屬性使用駝峰命名法
    • 特殊屬性名: class -> className; for -> htmlFor; tabindex -> tabIndex
    • 沒有子節(jié)點的React元素可以用 /> 結(jié)尾
    • 推薦:使用小括號包裹JSX,從而避免JS中自動插入分號陷阱
    3.JSX中使用JavaScript表達(dá)式
    /* JSX中使用JavaScript表達(dá)式 */ const name = 'Tom' const age = 19 const title = (<h1>hello {name} ! 年齡: {age}</h1> ) ReactDOM.render(title, document.getElementById('root'))/* 條件渲染 */ const isLoading = false const loadData = () => {if (isLoading) {return (<div>loading...</div>)}return (<div>數(shù)據(jù)加載完成,此處顯示加載后的數(shù)據(jù)</div>) }// 三元表達(dá)式 const loadData = () => {return isLoading ? (<div>loading...</div>) : (<div>數(shù)據(jù)加載完成</div>) }// 邏輯運算符 const loadData = () => {return isLoading && (<div>loading...</div>) }const load = (<h1>條件渲染:{loadData()}</h1> ) ReactDOM.render(load, document.getElementById('root'))
    4.JSX列表渲染
    /* 列表渲染 */ const songs = [{ id: 1, name: '癡心絕對'},{ id: 2, name: '阿拉斯加的海灣'},{ id: 3, name: '長安姑娘'}, ]const list = (<ul>{songs.map(item => {return (<li key={item.id}>{item.name}</li>)})}</ul> )ReactDOM.render(list, document.getElementById('root'))
    5.JSX樣式處理
    // 類名,外部引入 import './index.css'// 行內(nèi)樣式 const list = (<h1 className="title" style={{color: 'skyblue', backgroundColor: 'pink'}}>JSX的樣式處理</h1> )ReactDOM.render(list, document.getElementById('root'))

    總結(jié)

  • JSX是React的核心內(nèi)容
  • JSX表示在JS代碼中寫HTML結(jié)構(gòu),是React聲明式的體現(xiàn)
  • 使用JSX配合嵌入的JS表達(dá)式、條件渲染、列表渲染、可以描述任意UI結(jié)構(gòu)
  • 推薦使用類名給JSX添加樣式
  • React完全利用JS語言自身的能力來編寫UI,而不是造輪子增強(qiáng)HTML功能
  • (2)React組件

    組件介紹

    • 組件是React的一等公民,使用React就是在用組件
    • 組件表示頁面中的部分功能
    • 組合多個組件實現(xiàn)完整的頁面功能
    • 特點:可復(fù)用、獨立、可組合
    1.創(chuàng)建方式
    • 使用函數(shù)創(chuàng)建
    • 使用類創(chuàng)建
    • 抽離為獨立的JS文件
    2.React事件處理
    import React from 'react'/* React事件處理 */ // 使用類組件形式class App extends React.Component {// 事件處理程序handleClick() {console.log('單擊事件觸發(fā)了')}render() {return (<button type="" onClick={this.handleClick}>點我</button>)}}// 使用函數(shù)組件形式 function App() {function handleClick() {console.log('函數(shù)組件的點擊事件被觸發(fā)了')}return (// 和類組件相比,就沒有this,可以直接通過函數(shù)名<button type="" onClick={handleClick}>函數(shù)組件-點我</button>) }export default App
    3.React事件對象
    import React from 'react' /* React事件對象 (合成事件) */ // 使用類組件形式 class App extends React.Component { // 事件處理程序 handleClick(e) { // 阻止默認(rèn)行為 e.preventDefault() console.log('a標(biāo)簽單擊事件觸發(fā)了') console.log('事件對象:', e) } render() { return ( <a href="https://www.bilibili.com" onClick={this.handleClick}>B站</a> ) }} export default App
    4.有狀態(tài)組件/無狀態(tài)組件
    import React from 'react'/* React有無狀態(tài)組件 */ // 函數(shù)組件又叫做無狀態(tài)組件,類組件又叫做有狀態(tài)組件 // 狀態(tài)(state)即數(shù)據(jù) // 函數(shù)組件沒有自己的狀態(tài),只負(fù)責(zé)數(shù)據(jù)展示(靜) // 類組件有自己的狀態(tài),負(fù)責(zé)更新UI,讓頁面“動起來”/* state的基本使用 */ // 狀態(tài)是可以改變的,通過setState({要修改的數(shù)據(jù)})來修改數(shù)據(jù);不能直接修改state中的值 // setState() 1.修改狀態(tài) 2.更新UI // 數(shù)據(jù)驅(qū)動的思想// 使用類組件形式 class App extends React.Component {// constructor() {// super()// // 初始化狀態(tài)// this.state = {// count: 0// }// }// 簡化語法初始化statestate = {count: 0,test: 'a'}// render() {// return (// <div>// <h1>計數(shù)器:{this.state.count}</h1>// <button type="" onClick={// () => {// 這里的this指向外部環(huán)境,即render()方法,就是當(dāng)前組件的實例,所以可以正常執(zhí)行// this.setState({// count: this.state.count + 1// })// }// }>+1</button>// </div>// )// }// 抽離邏輯代碼// 解決this指向問題// 1.箭頭函數(shù)// 2.Function.prototype.bind()// 3.class的實例方法(也是利用箭頭函數(shù)this指向的特點)// 利用ES5的bind方法,將事件處理程序中的this與組件實例綁定到一起// constructor() {// constructor里的this也是指向?qū)嵗?/ super()// state也可以放在這里// this.state = {// count: 0// }// this.onIncrease = this.onIncrease.bind(this)// }// 事件處理程序// onIncrease() {// this.setState({// count: this.state.count + 1// })// }// 第三種改變this指向的方法onIncrease = () => {this.setState({count: this.state.count + 1})}render() {return (<div><h1>計數(shù)器:{this.state.count}</h1>{/*箭頭函數(shù)本身不綁定this,這里的this指向外部環(huán)境,即render()方法,就是當(dāng)前組件的實例,所以可以正常執(zhí)行 */}{/* <button type="" onClick={() => this.onIncrease()}>點我+1</button> */}<button type="" onClick={this.onIncrease}>+1</button></div>)} }export default App
    5.表單處理-受控組件
    import React from 'react'/* React表單處理 */ /* 1.受控組件:受到React控制的表單元素HTML中表單元素是可輸入的,也就是有自己可變的狀態(tài),而React中可變狀態(tài)通常保存在state中,并且只能通過setState()方法來修改;React將state與表單元素值value綁定到一起,由state的值來控制表單元素的值 */ // 步驟 // 1.在state中添加一個狀態(tài),作為表單元素的value值 // 2.給表單元素綁定change事件,將表單元素的值設(shè)置為state的值(控制表單元素值的變化)// 問題:每個表單元素都有一個單獨的事件處理程序 // 優(yōu)化步驟 // 1.給表單元素添加name屬性,名稱與state相同 // 2.根據(jù)表單元素類型獲取對應(yīng)值(有些表單是value,有的是checked) // 3.在change事件處理程序中通過[name]來修改對應(yīng)的state// 使用類組件形式 class App extends React.Component {// 簡化語法初始化statestate = {txt: '',content: '',city: 'bj',isChecked: false}handleChange = (e) => {this.setState({txt: e.target.value})}// 處理富文本框handleContent = e => {this.setState({content: e.target.value})}// 處理下拉框handleCity = e => {this.setState({city: e.target.value})}// 處理復(fù)選框// handleCheckBox = e => {// this.setState({// isChecked: e.target.checked// })// }/* 事件處理程序優(yōu)化*/handleAllChange = e => {// 獲取當(dāng)前DOM對象const target = e.target// 根據(jù)類型判斷獲取值const value = target.type === 'checkbox' ? target.checked : target.value// 獲取nameconst name = target.namethis.setState({[name]: value})}render() {return (<div>{/* 文本框 */}{/* <input type="text" name="txt" value={this.state.txt} onChange={this.handleChange} /> */}<input type="text" name="txt" value={this.state.txt} onChange={this.handleAllChange} />{/* 富文本框 */}{/* <textarea rows="" cols="" name="content" value={this.state.content} onChange={this.handleContent}></textarea> */}<textarea rows="" cols="" name="content" value={this.state.content} onChange={this.handleAllChange}></textarea>{/* 下拉框 */}{/* <select name="city" value={this.state.city} onChange={this.handleCity}> */}<select name="city" value={this.state.city} onChange={this.handleAllChange}><option value="sh">上海</option><option value="bj">北京</option><option value="wh">武漢</option></select><br/>{/* 復(fù)選框 */}{/* <input name="isChecked" type="checkbox" checked={this.state.isChecked} onChange={this.handleCheckBox}/> */}<input name="isChecked" type="checkbox" checked={this.state.isChecked} onChange={this.handleAllChange}/></div>)} }export default App
    6.表單處理-非受控組件
    import React from 'react'/* 2.非受控組件(不推薦)借助ref,使用原生DOM方式來獲取表單元素值ref的作用:獲取DOM或組件 */ // 使用步驟 // 1.使用React.createRef()方法創(chuàng)建一個ref對象 // 2.將創(chuàng)建好的ref對象添加到文本框中(關(guān)聯(lián)表單元素) // 3.通過ref對象獲取到文本框的值// 使用類組件形式 class App extends React.Component {constructor() {super()// 創(chuàng)建refthis.txtRef = React.createRef()}// 獲取文本框的值getTxt = () => {console.log('文本框的值為:', this.txtRef.current.value)}render() {return (<div><input type="text" ref={this.txtRef} /><button type="" onClick={this.getTxt}>獲取文本框的值</button></div>)} }export default App

    總結(jié)

  • 組件的兩種創(chuàng)建方式:函數(shù)組件和類組件
  • 無狀態(tài)(函數(shù))組件負(fù)責(zé)靜態(tài)結(jié)構(gòu)展示
  • 有狀態(tài)(類)組件負(fù)責(zé)更新UI,讓頁面動起來
  • 綁定事件注意this指向問題
  • 推薦使用受控組件來處理表單
  • 完全利用JS語言的能力創(chuàng)建組件,這是React的思想
  • 二、進(jìn)階

    (1)React組件進(jìn)階

    組件通訊介紹

    組件是獨立且封閉的單元,默認(rèn)情況下只能使用組件自己的數(shù)據(jù)。組件化過程中多個組件之間不可避免的要共享某些數(shù)據(jù)。為了實現(xiàn)這些功能,就需要打破組件的獨立封閉性,讓其與外界溝通。這個過程就是組件通訊。

    1.組件的props
    • props作用:接收傳遞給組件的數(shù)據(jù)
    • 傳遞數(shù)據(jù):給組件標(biāo)簽添加屬性
    • 接收數(shù)據(jù):函數(shù)組件通過參數(shù)props接收數(shù)據(jù),類組件通過this.props接收數(shù)據(jù)
    import React from 'react' // import ReactDOM from 'react-dom'/* props */ // 2.函數(shù)組件接收數(shù)據(jù) // const App = (props) => { // // props是一個對象 // console.log(props) // return ( // <div> // <h1>props: {props.name}</h1> // </div> // ) // }// 類組件接收數(shù)據(jù) class App extends React.Component {// 推薦使用props作為構(gòu)造函數(shù)參數(shù)constructor(props) {super(props)console.log(props)}render() {return (<div><h1>props: {this.props.name}</h1></div>)} }// 1.傳遞數(shù)據(jù) // ReactDOM.render(<App name="Tom" age={19}></App>, document.getElementById('root'))

    特點

    • 可以給組件傳遞任意類型的數(shù)據(jù)(字符串“ ”,非字符串直接用 { } 包裹;可以傳數(shù)字、數(shù)組、函數(shù)、jsx)
    • props是只讀的對象,只能讀取屬性的值,無法修改對象
    • 使用類組件時,如果寫了構(gòu)造函數(shù),應(yīng)該將props傳遞給super(),否則無法在構(gòu)造函數(shù)中獲取到props
    2.組件通訊的三種方式
    2.1 父組件傳給子組件
  • 父組件提供要傳遞的state數(shù)據(jù)

  • 給子組件標(biāo)簽添加屬性,值為state中的數(shù)據(jù)

  • 子組件中通過props接收父組件中傳遞的數(shù)據(jù)

  • import React from 'react' /* 組件通訊的三種方式 */ // 父組件傳給子組件 // 父組件 class Parent extends React.Component {state = {lastName: "wang"}render() {return (<div className="parent">父組件:<Child name={this.state.lastName}></Child></div>)} }// 子組件 const Child = (props) => {return (<div className="child"><p>子組件接收到父組件的數(shù)據(jù):{props.name}</p></div>) }export default Parent
    2.2 子組件傳給父組件

    **思路:**利用回調(diào)函數(shù),父組件提供回調(diào)函數(shù),子組件調(diào)用,將要傳遞的數(shù)據(jù)作為回調(diào)函數(shù)的參數(shù)。(和Vue是一樣的)

    **注意:**回調(diào)函數(shù)this指向的問題

  • 父組件提供一個回調(diào)函數(shù)(用于接收數(shù)據(jù))
  • 將該函數(shù)作為屬性的值,傳遞給子組件
  • 子組件通過props調(diào)用回調(diào)函數(shù)
  • 將子組件的數(shù)據(jù)作為參數(shù)傳遞給回調(diào)函數(shù)
  • import React from 'react'/* 組件通訊的三種方式 */// 子組件傳給父組件 // 父組件 class Parent extends React.Component {state = {parentMsg: ''}// 提供回調(diào)函數(shù),用來接收數(shù)據(jù)getChildMsg = (data) => {console.log('接收到子組件中傳遞過來的數(shù)據(jù):', data)this.setState({parentMsg: data})}render() {return (<div className="parent">父組件:{this.state.parentMsg}<Child getMsg={this.getChildMsg}></Child></div>)} }// 子組件 class Child extends React.Component {state = {msg: "呷哺呷哺"}handleClick = () => {// 子組件調(diào)用父組件傳遞過來的回調(diào)函數(shù)this.props.getMsg(this.state.msg)}render() {return (<div className="child">子組件:<button onClick={this.handleClick}>點我,給父組件傳遞數(shù)據(jù)</button></div>)} }export default Parent
    2.3 兄弟組件之間通訊

    **思路:**將共享狀態(tài)提升到最近的公共父組件中,由公共父組件管理這個狀態(tài)(狀態(tài)提升

    • 公共父組件職責(zé):1.提供共享狀態(tài);2.提供操作共享狀態(tài)的方法
    • 要通訊的子組件只要通過props接收狀態(tài)或操作狀態(tài)的方法
    import React from 'react'/* 組件通訊的三種方式 *//* 兄弟組件之間通訊 */ // 公共父組件 class Parent extends React.Component {// 提供共享狀態(tài)state = {count: 0}// 提供修改共享狀態(tài)的方法onIncrease = () => {this.setState({count: this.state.count + 1})}render() {return (<div><Child1 count={this.state.count}/><Child2 onIncrease={this.onIncrease}/></div>)} }// 子組件1 const Child1 = (props) => {return (<h1>計數(shù)器:{props.count}</h1>) }// 子組件2 const Child2 = (props) => {return (<button onClick={() => props.onIncrease()}>點我+1</button>) }export default Parent
    3.Context

    **作用:**跨組件傳遞數(shù)據(jù)(比如:主題、語言等)

    使用步驟:

  • 調(diào)用 React.createContext() 創(chuàng)建 Provider(提供數(shù)據(jù))和 Consumer(消費數(shù)據(jù))兩個組件

  • 使用 Provider 組件作為父節(jié)點

  • 設(shè)置value,表示要傳遞的數(shù)據(jù)

  • 使用Consumer組件接收數(shù)據(jù)

  • import React from 'react'/* Context */// 1.創(chuàng)建context得到兩個組件 const {Provider, Consumer} = React.createContext()class App extends React.Component {render() {return (// 2.使用 Provider 組件作為父節(jié)點// 3.設(shè)置value,表示要傳遞的數(shù)據(jù)<Provider value="pink"><div><Node/></div></Provider>)} }const Node = (props) => {return (<div>我是Node節(jié)點<SubNode/></div>) }const SubNode = (props) => {return (<div>我是SubNode節(jié)點<Child/></div>) }const Child = (props) => {return (<div>我是Child節(jié)點{/* 4.使用Consumer組件接收數(shù)據(jù) */}<Consumer>{data => <h1>傳遞來的值 -- {data}</h1>}</Consumer></div>) }export default App

    總結(jié):

  • 如果兩個組件是”遠(yuǎn)房親戚“(比如多層嵌套)可以使用Context實現(xiàn)組件通訊
  • Context提供了兩個組件:Provider和Consumer
  • Provider組件:用來提供數(shù)據(jù)
  • Consumer組件:用來消費數(shù)據(jù)
  • 4.props深入
    4.1 children屬性
    • children屬性:表示組件標(biāo)簽的子節(jié)點。當(dāng)組件標(biāo)簽有子節(jié)點時,props就會有該屬性

    • children屬性與普通的props一樣,值可以是任意值(文本、React元素、組件,甚至是函數(shù))

    /* children屬性*//* children為文本節(jié)點 */// const App = (props) => {// console.log(props)// return (// <div>// <h1>組件標(biāo)簽的子節(jié)點:</h1>// {props.children}// </div>// )// }// ReactDOM.render(<App>我是子節(jié)點</App>, document.getElementById('root'))/* children為JSX或組件 */// const App = (props) => {// console.log(props)// return (// <div>// <h1>組件標(biāo)簽的子節(jié)點:</h1>// {props.children}// </div>// )// }// ReactDOM.render(<App><p>我是子節(jié)點,是一個p標(biāo)簽</p></App>, document.getElementById('root'))// const Test = () => <button>我是按鈕組件</button>// ReactDOM.render(<App><Test/></App>, document.getElementById('root'))/* children為函數(shù) */const App = (props) => {console.log(props)return (<div><h1>組件標(biāo)簽的子節(jié)點:</h1>{props.children()}</div>)}// ReactDOM.render(<App>{ () => console.log('這是一個函數(shù)子節(jié)點')}</App>, document.getElementById('root'))
    4.2 props校驗
    • 對于組件來說,props是外來的,無法保證組件使用者傳入什么格式的數(shù)據(jù)

    • 如果傳入的數(shù)據(jù)格式不對,可能會導(dǎo)致組件內(nèi)部報錯

    • 關(guān)鍵問題:組件的使用者不知道明確的錯誤原因

    • props校驗:允許在創(chuàng)建組件的時候,就指定props的類型、格式等

    • 作用:捕獲使用組件時因為props導(dǎo)致的錯誤,給出明確的錯誤提示,增加組件的健壯性

      使用步驟:

    • 安裝包:prop-types (yarn add prop-types / npm i prop-types)

    • 導(dǎo)入prop-types包

    • 使用 組件名.propTypes = {} 來給組件的props添加校驗規(guī)則

    • 校驗規(guī)則通過 PropTypes 對象來指定

      /* props校驗 */ // 導(dǎo)入 import PropTypes from 'prop-types'const App = (props) => {const arr = props.colorsconst lis = arr.map((item, index) => {return (<li key={index}>{item}</li>)})return (<ul>{lis}</ul>) }// 添加props校驗 App.propTypes = {colors: PropTypes.array }// ReactDOM.render(<App colors={19}></App>, document.getElementById('root')) // 會有明確的錯誤提示 // Warning: Failed prop type: Invalid prop `colors` of type `number` supplied to `App`, expected `array`.// ReactDOM.render(<App colors={['red', 'blue']}></App>, document.getElementById('root'))
    • 約束規(guī)則:

    • 常見類型:array、bool、func、number、object、string

    • React元素類型:element

    • 必填項:isRequired

    • 特定結(jié)構(gòu)的對象:shape({ })

    import React from 'react'/* props校驗-約束規(guī)則*/// 導(dǎo)入import PropTypes from 'prop-types'const App = (props) => {return (<div><h1>props校驗:</h1></div>)}/* 添加props校驗屬性 a 的類型:數(shù)值(number)屬性 fn 的類型:函數(shù)(func)并且為必填項屬性 tag 的類型:React元素(element)屬性 filter 的類型:對象({ area:'上海', price: 1999})*/App.propTypes = {a: PropTypes.number,fn: PropTypes.func.isRequired,tag: PropTypes.element,filter: PropTypes.shape({area: PropTypes.string,price: PropTypes.number})}export default App``` ###### 4.3 props的默認(rèn)值- 場景:分頁組件 → 每頁顯示條數(shù) - 作用:給props設(shè)置默認(rèn)值,在未傳入props時生效```jsx import React from 'react'/* props的默認(rèn)值 */const App = (props) => {console.log(props)return (<div><h1>props的默認(rèn)值:{props.pageSize}</h1></div>) }// 添加props默認(rèn)值 App.defaultProps = {pageSize: 10 }// ReactDOM.render(<App pageSize={20}></App>, document.getElementById('root')) // 這是顯示的就是 20 而不是 10export default App

    組件的生命周期

    1. 概述
    • 意義:組件的生命周期有助于理解組件的運行方式、完成更復(fù)雜的組件功能,分析組件錯誤原因等
    • 組件的生命周期:組件從被創(chuàng)建到掛載到頁面中運行,再到組件不用時卸載的過程
    • 生命周期的每個階段總是伴隨著一些方法調(diào)用,這些方法就是生命周期的鉤子函數(shù)
    • 鉤子函數(shù)作用:為開發(fā)人員在不同階段操作組件提供了時機(jī)
    • 只有類組件才有生命周期
    2. 生命周期的三個階段
    • 每個階段的執(zhí)行時機(jī)
    • 每個階段鉤子函數(shù)的執(zhí)行順序
    • 每個階段鉤子函數(shù)的作用
  • 創(chuàng)建時(掛載階段)

    • 執(zhí)行時機(jī):組件創(chuàng)建時(頁面加載時)

    • 執(zhí)行順序:constructor() → render() → componentDidMount()

      鉤子函數(shù)觸發(fā)時機(jī)作用
      constructor創(chuàng)建組件時,最先執(zhí)行1.初始化state;2.為事件處理程序綁定this
      render每次組件渲染都會觸發(fā)渲染UI(注意:不能調(diào)用setState()
      componentDidMount組件掛載(完成DOM渲染后)1.發(fā)送網(wǎng)絡(luò)請求;2.DOM操作
  • import React from 'react'/* 組件生命周期 */ // 創(chuàng)建時(掛載階段) class App extends React.Component {constructor() {super()// 初始化statethis.state = {count: 0}// 處理this綁定問題// const title = document.getElementById('title')// 此時DOM還沒渲染,拿不到DOM// console.log(title) 結(jié)果:nullconsole.warn('生命周期鉤子函數(shù): 1.constructor')}componentDidMount() {// const title = document.getElementById('title')// 1.此時已經(jīng)完成DOM渲染,可以拿到DOM,進(jìn)行DOM操作// console.log(title)// 2.發(fā)送AJAX請求,獲取遠(yuǎn)程數(shù)據(jù)// axios.get('http://api....')console.warn('生命周期鉤子函數(shù): 3.componentDidMount')}render() {// 在render()里調(diào)用this.setState()會造成遞歸更新console.warn('生命周期鉤子函數(shù): 2.render')// 渲染返回內(nèi)容return (<div><h1 id="title">統(tǒng)計豆豆被打的次數(shù):</h1><button id="btn">打豆豆</button></div>)} }export default App
  • 更新時(更新階段)

    • 執(zhí)行時機(jī):1.setState(); 2.forceUpdate(); 3.組件接收到新的props

    • 說明:以上三者任意一種變化,組件都會重新渲染

    • 執(zhí)行順序:render() → componentDidUpdate()

      鉤子函數(shù)觸發(fā)時機(jī)作用
      render每次組件渲染都會觸發(fā)渲染UI(與 掛載階段 是同一個render)
      componentDidUpdate組件更新(完成DOM渲染)后1.發(fā)送網(wǎng)絡(luò)請求;2.DOM操作;注意:如果要setState()必須放在一個if條件中
      import React from 'react'/* 組件生命周期 */ // 更新時(更新階段) class App extends React.Component {constructor(props) {super(props)// 初始化statethis.state = {count: 0}}handleClick = () => {// 1.調(diào)用setState,此時父組件會重新渲染this.setState({count: this.state.count + 1})// 3.演示強(qiáng)制更新,即使屬性沒有更新也會強(qiáng)制更新// this.forceUpdate()}render() {return (<div>{/* 2.接收到新屬性,子組件也會更新 */}<Counter count={this.state.count}></Counter><button id="btn" onClick={this.handleClick}>打豆豆</button></div>)} }class Counter extends React.Component {render() {// 2.接收到新屬性,子組件也會更新console.warn('子組件——生命周期鉤子函數(shù): render')return (<h1 id="title">統(tǒng)計豆豆被打的次數(shù):{this.props.count}</h1>)}componentDidUpdate(prevProps) {console.warn('子組件——生命周期鉤子函數(shù): componentDidUpdate')// 可以獲取DOM// const title = document.getElementById('title')// console.log(title.innerHTML)// 注意:如果要調(diào)用setState()更新狀態(tài),必須要放在if條件中。否則也會造成遞歸更新// 原因:如果直接調(diào)用setState()更新狀態(tài),會再去執(zhí)行render(),render()執(zhí)行完會立即去執(zhí)行componentDidUpdate(),從而造成遞歸調(diào)用。// 做法:比較更新前后的props是否相同,來決定是否重新渲染組件console.log('prevProps: ', prevProps, '--currentProps: ', this.props)if (prevProps !== this.props) {this.setState({})// 發(fā)送ajax請求}/* 這里點擊“打豆豆”按鈕,會打印兩次結(jié)果:prevProps: {count: 0} --currentProps: {count: 1}prevProps: {count: 1} --currentProps: {count: 1}原因:第一次是點擊了按鈕,父組件狀態(tài)更新,子組件props發(fā)生變化,鉤子函數(shù)順序執(zhí)行到componentDidUpdate(),第二次是因為走了if里面的語句,調(diào)用完setState后,重新render后又要立即去執(zhí)行componentDidUpdate(),只不過此時沒有改變父組件狀態(tài),所以前后props是一樣的*/} }export default App
  • 卸載時(卸載階段)

    • 執(zhí)行時機(jī):組件從頁面中消失

    • 鉤子函數(shù)componentWillUnmount()

      鉤子函數(shù)觸發(fā)時機(jī)作用
      componentWillUnmount組件卸載(從頁面中消失)執(zhí)行清理工作(比如:清理定時器等)
      import React from 'react'/* 組件生命周期 */ // 卸載時(卸載階段) class App extends React.Component {constructor(props) {super(props)// 初始化statethis.state = {count: 0}}handleClick = () => {this.setState({count: this.state.count + 1})}render() {return (<div>{this.state.count > 3? <p>豆豆被打西內(nèi)了</p>: <Counter count={this.state.count}></Counter>}<button id="btn" onClick={this.handleClick}>打豆豆</button></div>)} }class Counter extends React.Component {componentDidMount() {// 開啟定時器this.timerId = setInterval(() => {console.log('定時器正在執(zhí)行~')}, 1000)}render() {return (<h1 id="title">統(tǒng)計豆豆被打的次數(shù):{this.props.count}</h1>)}componentWillUnmount() {console.warn('生命周期鉤子函數(shù):componentWillUnmount')// 清理定時器clearInterval(this.timerId)} }export default App
  • 3. 不常用鉤子函數(shù)

    **介紹:**react庫不斷更新,新老不匹配,移除舊的不常用鉤子函數(shù),加入新的鉤子函數(shù)

    舊版的生命周期,創(chuàng)建和更新的componentWillxxx不用了

    新版完整的生命周期,這兩個新的getxxxx也不是很推薦使用

    render-props和高階組件

    1. React組件復(fù)用
  • 概述

    • 思考:如果兩個組件中的部分功能相似或相同,該如何處理?
    • 處理方式:復(fù)用相似的功能(聯(lián)想函數(shù)封裝)
    • 復(fù)用什么?1.state 2.操作state的方法(組件狀態(tài)邏輯)
    • 兩種方式:1.render props模式 2.高階組件(HOC:high order component)
    • 注意:這兩種模式不是新的API,而是利用React自身特點的編碼技巧,演化而成的固定模式(寫法)
  • 2. render props模式

    (只是個名字,不一定就是使用 render)

    context其實用的就是render props模式,而且是children屬性

    思路分析

    • 思路:將要復(fù)用的state和操作state的方法封裝到一個組件中
    • 問題1:如何拿到該組件中復(fù)用的state?
    • 在使用組件時,添加一個值為函數(shù)的prop,通過函數(shù)參數(shù)來獲取(需要組件內(nèi)部實現(xiàn))
    • 問題2:如何渲染任意的UI?
    • 使用該函數(shù)的返回值作為要渲染的UI內(nèi)容(需要組件內(nèi)部實現(xiàn))

    使用步驟

  • 創(chuàng)建Mouse組件,在組件中提供復(fù)用的狀態(tài)邏輯代碼(1.狀態(tài);2.操作狀態(tài)的方法)

  • 將要復(fù)用的狀態(tài)作為props.render(state)方法的參數(shù),暴露到組件外部

  • 使用props.render()的返回值作為要渲染的內(nèi)容

    import React from 'react' import PropTypes from 'prop-types' /* render props模式 */// 導(dǎo)入圖片資源 const catImgSrc = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.qiantucdn.com%2F58pic%2F27%2F51%2F73%2F30V58PICg4M_1024.jpg%21%2Ffw%2F780%2Fwatermark%2Furl%2FL3dhdGVybWFyay12MS4zLnBuZw%3D%3D%2Falign%2Fcenter%2Fcrop%2F0x1009a0a0&refer=http%3A%2F%2Fpic.qiantucdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1634716498&t=8cf797a6f75a9a570b1c760dc682c9e5"// 創(chuàng)建Mouse組件 class Mouse extends React.Component {// 鼠標(biāo)位置state(狀態(tài))state = {x: 0,y: 0}// 鼠標(biāo)移動處理程序(操作狀態(tài)的方法)handleMouseMove = (e) => {this.setState({x: e.clientX,y: e.clientY})}// 監(jiān)聽鼠標(biāo)移動事件componentDidMount() {window.addEventListener('mousemove', this.handleMouseMove)}// 在組件卸載時移除事件綁定componentWillUnmount() {window.removeEventListener('mousemove', this.handleMouseMove)}render() {// return null// 沒有渲染任何ui結(jié)構(gòu)// return this.props.render(this.state)// 用children屬性替換renderreturn this.props.children(this.state)} }// 添加props校驗 Mouse.propTypes = {children: PropTypes.func.isRequired }class App extends React.Component {constructor(props) {super(props)console.log(props)}render() {return (<div><h1>render props 模式</h1>{/* 這里的mouse形參,拿到的就是上面Mouse組件的this.state */}{/* <Mouse render={(mouse) => {// 可以拿到狀態(tài),具體展示形式就可以在使用組件的地方自行定義return <p>鼠標(biāo)位置:{mouse.x},{mouse.y}</p>}}></Mouse> */}{/* 貓捉老鼠 */}{/* <Mouse render={(mouse) => {return <img src={catImgSrc} alt="貓" width={100} style={{position: 'absolute',top: mouse.y - 50,left: mouse.x - 50}}/>}}></Mouse> */}{/* children屬性代替render */}<Mouse>{(mouse) => {return <p>children拿到鼠標(biāo)位置:{mouse.x},{mouse.y}</p>}}</Mouse>{/* children屬性代替render */}{/* 貓捉老鼠 */}<Mouse>{(mouse) => {return <img src={catImgSrc} alt="貓" width={100} style={{position: 'absolute',top: mouse.y - 50,left: mouse.x - 50}}/>}}</Mouse></div>)} }export default App
  • 代碼優(yōu)化

  • 推薦:給render props模式添加 props校驗
  • 應(yīng)該在組件卸載時解除mousemove時間綁定
  • 3. 高階組件

    概述

    • 目的:實現(xiàn)狀態(tài)邏輯復(fù)用
    • 采用包裝(裝飾)模式,比如說:手機(jī)殼
    • 手機(jī):獲取保護(hù)功能
    • 手機(jī)殼:提供保護(hù)功能
    • 通過包裝組件,增強(qiáng)組件功能

    思路分析

    • 高階組件(HOC,Higher-Order Component)是一個函數(shù),接收要包裝的組件,返回增強(qiáng)后的組件。
    • 高階組件內(nèi)部創(chuàng)建一個類組件,在這個類組件中提供復(fù)用的狀態(tài)邏輯代碼,通過prop將復(fù)用的狀態(tài)傳遞給包裝組件WrappedComponent

    使用步驟

  • 創(chuàng)建一個函數(shù),名稱約定以with開頭
  • 指定函數(shù)參數(shù),參數(shù)應(yīng)該以大寫字母開頭(作為要渲染的組件)
  • 在函數(shù)內(nèi)部創(chuàng)建一個類組件,提供復(fù)用的狀態(tài)邏輯代碼,并返回
  • 在該組件中,渲染參數(shù)組件,同時將狀態(tài)通過props傳遞給參數(shù)組件
  • 調(diào)用該高階組件,傳入要增強(qiáng)的組件,通過返回值拿到增強(qiáng)后的組件,并將其渲染到頁面中。
  • 設(shè)置displayName

    • 使用高階組件存在的問題: 得到的兩個組件名稱相同
    • 原因:默認(rèn)情況下,React使用組件名稱作為displayName
    • 解決方式:為高階組件設(shè)置displayName便于調(diào)試時區(qū)分不同的組件
    • displayName的作用:用于設(shè)置調(diào)試信息(React Developer Tools信息)

    傳遞props

    • 問題:props丟失
    • 原因:高階組件沒有往下傳遞props
    • 解決方式:渲染W(wǎng)rappedComponent時,將state和this.props一起傳遞給組件
    import React from 'react' /* 高階組件 */// 導(dǎo)入圖片資源 const catImgSrc = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.qiantucdn.com%2F58pic%2F27%2F51%2F73%2F30V58PICg4M_1024.jpg%21%2Ffw%2F780%2Fwatermark%2Furl%2FL3dhdGVybWFyay12MS4zLnBuZw%3D%3D%2Falign%2Fcenter%2Fcrop%2F0x1009a0a0&refer=http%3A%2F%2Fpic.qiantucdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1634716498&t=8cf797a6f75a9a570b1c760dc682c9e5"// 創(chuàng)建高階組件函數(shù) function withMouse(WrappedComponent) {// 該組件提供復(fù)用的狀態(tài)邏輯class Mouse extends React.Component {// 鼠標(biāo)狀態(tài)state = {x: 0,y: 0}handleMouseMove = e => {this.setState({x: e.clientX,y: e.clientY})}// 控制鼠標(biāo)狀態(tài)邏輯componentDidMount() {window.addEventListener('mousemove', this.handleMouseMove)}componentWillUnmount() {window.removeEventListener('mousemove', this.handleMouseMove)}render() {console.log('Mouse: ', this.props)// 將state和this.props一起傳遞給組件return <WrappedComponent {...this.state} {...this.props}></WrappedComponent>}}// 設(shè)置displayNameMouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`return Mouse }function getDisplayName(WrappedComponent) {return WrappedComponent.displayName || WrappedComponent.name || 'Component' }// 用來測試高階組件 const Position = props => {console.log('Position: ', props)return (<p>鼠標(biāo)當(dāng)前位置:(x: {props.x}, y: {props.y})</p>) }// 貓捉老鼠組件 const Cat = props => (<imgsrc={catImgSrc}alt="cat"width={100}style={{position: 'absolute',top: props.y - 50,left: props.x - 50}}/> )// 獲取增強(qiáng)后的組件 const MousePosition = withMouse(Position) const MouseCat = withMouse(Cat)class App extends React.Component {constructor(props) {super(props)console.log(props)}render() {return (<div><h1>高階組件</h1>{/* 渲染高階組件 */}{/* 這里的a="1"相當(dāng)于是傳給了高階函數(shù)里的Mouse組件 */}<MousePosition a="1"></MousePosition><MouseCat></MouseCat></div>)} }export default App

    總結(jié)

  • 組件通訊是構(gòu)建React應(yīng)用必不可少的一環(huán)
  • props的靈活性讓組件更加強(qiáng)大
  • 狀態(tài)提升是React組件的常用模式
  • 組件生命周期有助于理解組件的運行過程
  • 鉤子函數(shù)讓開發(fā)者可以在特定的時機(jī)執(zhí)行某些功能
  • render props模式和高階組件都可以實現(xiàn)組件狀態(tài)邏輯復(fù)用
  • 組件極簡模型:(state, props)=> UI
  • 總結(jié)

    以上是生活随笔為你收集整理的从零开始的React学习(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。