从零开始的React学习(一)
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)問題:
一、基礎(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é)
(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 App3.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 App4.有狀態(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 App5.表單處理-受控組件
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 App6.表單處理-非受控組件
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é)
二、進(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ù)
特點
- 可以給組件傳遞任意類型的數(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ù)
2.2 子組件傳給父組件
**思路:**利用回調(diào)函數(shù),父組件提供回調(diào)函數(shù),子組件調(diào)用,將要傳遞的數(shù)據(jù)作為回調(diào)函數(shù)的參數(shù)。(和Vue是一樣的)
**注意:**回調(diào)函數(shù)this指向的問題
2.3 兄弟組件之間通訊
**思路:**將共享狀態(tài)提升到最近的公共父組件中,由公共父組件管理這個狀態(tài)(狀態(tài)提升)
- 公共父組件職責(zé):1.提供共享狀態(tài);2.提供操作共享狀態(tài)的方法
- 要通訊的子組件只要通過props接收狀態(tài)或操作狀態(tài)的方法
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ù)
總結(jié):
4.props深入
4.1 children屬性
-
children屬性:表示組件標(biāo)簽的子節(jié)點。當(dāng)組件標(biāo)簽有子節(jié)點時,props就會有該屬性
-
children屬性與普通的props一樣,值可以是任意值(文本、React元素、組件,甚至是函數(shù))
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')) -
常見類型:array、bool、func、number、object、string
-
React元素類型:element
-
必填項:isRequired
-
特定結(jié)構(gòu)的對象:shape({ })
約束規(guī)則:
組件的生命周期
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操作
更新時(更新階段)
-
執(zhí)行時機(jī):1.setState(); 2.forceUpdate(); 3.組件接收到新的props
-
說明:以上三者任意一種變化,組件都會重新渲染
-
執(zhí)行順序:render() → componentDidUpdate()
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鉤子函數(shù)觸發(fā)時機(jī)作用 render 每次組件渲染都會觸發(fā) 渲染UI(與 掛載階段 是同一個render) componentDidUpdate 組件更新(完成DOM渲染)后 1.發(fā)送網(wǎng)絡(luò)請求;2.DOM操作;注意:如果要setState()必須放在一個if條件中
卸載時(卸載階段)
-
執(zhí)行時機(jī):組件從頁面中消失
-
鉤子函數(shù)componentWillUnmount()
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鉤子函數(shù)觸發(fā)時機(jī)作用 componentWillUnmount 組件卸載(從頁面中消失) 執(zhí)行清理工作(比如:清理定時器等)
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)化
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
使用步驟
設(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一起傳遞給組件
總結(jié)
總結(jié)
以上是生活随笔為你收集整理的从零开始的React学习(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 还不会发包?30S教会你
- 下一篇: 实习报告收集