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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

React中级学习(第一天)

發布時間:2023/12/13 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 React中级学习(第一天) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Props深入

children

  • 作用 : 獲取組件標簽子節點
  • 獲取方式 : this.props.children
<App>此處的內容,就是組件的 children,將來通過組件的 props.children 就可以獲取到這些子節點了 </App>

props 校驗

  • 作用:規定組件props的類型約束, 減少開發中的錯誤

  • prop-types 校驗規則

  • 安裝 : yarn add prop-types

  • 導入 : import Propypes from 'prop-types'

  • 給組件添加校驗規則

    // 要對某個組件里的某個屬性進行校驗 Child.propTypes = {// age 表示要校驗的屬性名稱// number 表示類型是數字// isRequied 表示必填項age : PropTypes.number.isRequired,name : PropTypes.string,arr : PropTypes.array,fn : PropTypes.func,isOK : PropTypes.bool,// 任何可被渲染的元素(包括數字、字符串、元素或數組)// (或 Fragment) 也包含這些類型。optionalNode: PropTypes.node,// 你可以讓你的 prop 只能是特定的值,指定它為 枚舉類型。num : PropTypes.oneOf(['News', 'Photos']).isRequired,// 一個對象可以是幾種類型中的任意一個類型optionalUnion: PropTypes.oneOfType([PropTypes.string,PropTypes.number]).isRequired, }

props的默認值

  • 可以通過 組件.defaultProps = {} 這樣的方式來給組件添加默認值
  • 默認值在用戶沒有傳遞該組件時會生效,如果用戶傳遞了該屬性,那么就會使用用戶傳遞的屬性了
// 默認值 Child.defaultProps = {age : 10 }

生命周期

  • 生命周期圖譜
  • 圖示:

第一階段 : 掛載階段

  • 觸發時機 : 組件第一次被渲染的時候, 進入頁面的時候觸發
  • 三個鉤子函數
    • constructor() : 初始化state
    • render() : 渲染UI
    • componentDidMount() : 1.操作DOM 2. 發送ajax請求
  • 觸發順序 : constructor --> render --> componentDidMount
// 類組件class Child extends React.Component {//1.1. 構造函數// 初始化數據constructor() { super()this.state = {name :'zs'}console.warn('constructor');}//1.2. 渲染UI render () {console.warn('render');return (<div><p>哈哈 {this.state.name}</p></div>)}//1.3. 掛載之后 渲染之后// 操作DOM ,發送ajaxcomponentDidMount () {console.warn('componentDidMount');}}

第二階段 : 更新階段

  • 執行順序 : render --> componentDidUpdate
  • 三種觸發組件更新的方式
    • setState() : 修改 state 的值
    • new Props : 表示組件接收到一個新的 props 值。在父子組件關系中,當父組件中狀態更新時,最新的 props 會自動傳入到子組件中,從而觸發子組件的重新渲染。不管是函數組件還是class組件,都會觸發重新渲染
    • forceUpdate() : 表示強制組件重新渲染 (一般不會用 知道就好)
  • 注意點
  • 注意1 : componentDidUpdate 鉤子函數中獲取到的是 更新后的 DOM 內容
    • 想獲取之前的, 使用 componentDidUpdate (preProps,preState) {
    • 參數是之前的props 和 state
  • 注意2 : 在 componentDidUpdate 鉤子函數中,不能直接調用 setState() 否則,會遞歸渲染,造成死循環。如果要調用 setState(),應該放在一個 條件判斷 中
class Parent extends React.Component { state = {pmsg :'撩妹'}render () { return <div><button onClick={this.updateProps2Child}>按鈕修改props</button><Child msg={ this.state.pmsg }></Child></div>}updateProps2Child = () => { // 演示2 : 修改父的state 其實就是修改 child 的props , 重新調用 child 的renderthis.setState({pmsg : '撩漢'})} }//2. 類組件class Child extends React.Component {state = {name :'zs'}//2.1. 渲染UI render () {console.warn('render');return (<div><p>哈哈 {this.state.name}</p><p>父傳過來的 : { this.props.msg }</p><button onClick={this.updateName}>按鈕</button></div>)}//更新state 的name 數據updateName = () => { // 演示1 : setState 重新調用 renderthis.setState({name : 'ls'})// 演示3 : forceUpdate 重新調用 renderthis.forceUpdate()}// 2.2 組件更新// 上一次的 props 和 上一次的state componentDidUpdate (preProps,preState) { console.warn('組件更新之前的數據', preState);// this.state 當前最新的state console.warn('組件更新之后的數據',this.state); // 有條件的渲染 不然會造成死循環if(this.state.name !== preState.name) {this.setState({name : this.state.name})}}}

第三階段 : 卸載階段

  • componentWillUnmount:在組件卸載時會觸發,也就是 組件從頁面中消失的時候
  • 作用:執行清理工作
    • 比如:清理掉 定時器、解綁手動綁定的事件 等
// 第一步 : 在父組件里 點擊按鈕, 把 子組件給銷毀 class Parent extends React.Component { ...render () { return <div><button onClick={this.changeShow}>按鈕修改props</button>{ this.state.isShow && (<Child msg={ this.state.pmsg }></Child>) }</div>}changeShow = () => { // 點擊按鈕 子組件被銷毀卸載this.setState({isShow : false})} }// 第二步 : 在 Child 組件里 componentDidMount () {//1. 開始定時器this.timerId = setInterval(() => {console.log('好嗨喲');}, 1000);//2. 給window注冊鼠標觸摸事件window.addEventListener('mousemove', this.handleMouseMove) }// 觸摸事件處理函數 handleMouseMove = (e) => { console.log(e.clientX); }// 第三步 : 在將要卸載的鉤子函數里 清除定時器和 移除鼠標移動事件 // 將要卸載 componentWillUnmount () { //1. 清除定時器clearInterval(this.timerId)//2. 移除鼠標觸摸事件window.removeEventListener('mousemove',this.handleMouseMove) }

render-props 和 高階組件 的介紹

  • 什么情況下 會使用這兩種模式 ? 復用

  • 當兩個組件或者多個組件有一部分state 和 操作 state 的方法 相同或者相似的時候, 就可以將這些代碼邏輯使用這兩種模式來實現復用

  • 目的 : 狀態邏輯復用 ==> 通俗點說 : 另一種封裝形式

  • 要復用的內容為 :

    • state
    • 操作 state 的方法
  • 注意

    • 不管是高階組件還是 render-props 模式, 都要將狀態邏輯封裝在一個組件中
    • 并且這個組件只提供狀態和操作狀態的方法邏輯
    • 這個組件不提供要渲染的UI結構, 因為要渲染的內容不確定
  • 學習注意 :

    • 思想重于代碼

render-props 的使用

拷貝 Mouse.js 并簡單介紹

  • state : {x,y} 鼠標坐標
  • 注冊鼠標移動事件和移除 事件
  • 移動事件吹函數 保存鼠標位置

演示1 : 鼠標位置

// 位置 // 1. 使用 mouse組件 添加一個render屬性, 值類型為一個函數 // 2. 可以得到一個mouse 位置坐標 // 3. 通過return 什么, 頁面就會顯示什么 ReactDOM.render(<Mouse render={(mouse) => { console.log(mouse);return <h1>{mouse.x} - {mouse.y}</h1> }}/>,document.getElementById('root'))

演示2 :移動貓

// 引入圖片 import cat from './images/cat.png'// 渲染 ReactDOM.render(<Mouse render={mouse => { return <img style={{ position : "absolute", left:mouse.x-64, top:mouse.y-64 }} src={cat} alt=''/>} }/>,document.getElementById('root'))

總結使用共同步驟

  • 1.給 Mouse 組件傳遞 render 屬性 ( render屬性的值 是一個函數 )
  • 2.通過 render 函數屬性的參數 來獲取組件內部復用的狀態 (比如 : 鼠標位置數據)
  • 3 通過render函數屬性的返回值來指定最終要渲染在 頁面中的內容

####分析Mouse 組件內容

  • Mouse 組件 只負責
    • 提供 鼠標位置 state
    • 提供操作數據位置的邏輯代碼
  • 注意 : Mouse 組價 自身不指定要渲染的內容, 因為 Mouse 組件自身要渲染的什么內容
    • 實際上是由用戶在使用該組件時指定的
  • 思想 : Mouse 組件通過調用 props.render() 方法, 將組件內部的狀態暴露到組件外部, 這樣, 用戶在使用該組件時, 就可以通過 render 屬性的參數來獲取到組件內部的狀態了
// 封裝 Mouse 組件 Mouse.js, // 實現鼠標位置的復用 // 狀態邏輯復用:1 state 2 操作狀態 class Mouse extends React.Component {// 提供鼠標位置的狀態state = {x: 0,y: 0}// 監聽鼠標位置componentDidMount() {window.addEventListener('mousemove', this.handleMouseMove)}// 組件卸載時執行清理工作:解綁事件componentWillUnmount() {window.removeEventListener('mousemove', this.handleMouseMove)}// 更新鼠標位置handleMouseMove = e => {this.setState({x: e.clientX,y: e.clientY})}render() {// 通過 props 來獲取到傳遞給組件的屬性 render// 因為 render 是一個函數,所以,就可以調用// 在調用 render 函數時,將組件內部的狀態,傳遞給 render 函數// 最終,通過 render 的形參,就可以在組件外部獲取到組件內部的狀態了// this.props.render(this.state)// return null// 通過 render 函數的返回值來指定要渲染的內容// 所以,在組件內部直接使用 render 函數的返回值來作為該組件要渲染的內容return this.props.render(this.state)} }

使用 children 代替 render 屬性

  • 注意 : 不是該模式叫 render-props 模式, 就必須使用render 屬性
    • 實際上, 只要有一個屬性來告訴組件要渲染什么內容, 其實這就是 render-props 模式了
  • 推薦 : 使用 children 代替 render 屬性
  • 使用 children 演示位置和貓
// 1 . 位置 ReactDOM.render(<Mouse>{(mouse) => { return <p>{mouse.x} - { mouse.y }</p> # +} } </Mouse>, document.getElementById('root')) // 2 . 貓 ReactDOM.render(<Mouse>{mouse => { return <img style={{ position:'absolute', left:mouse.x-64, top:mouse.y-64 }} src={cat} alt=""/> # +} } </Mouse>, document.getElementById('root'))// 3. Mouse.js 內部 render() {// 改為 children return this.props.children(this.state) }

使用場景

  • 場景1 : 之前的 Context 使用的就是這個模式
// 提供數據 <Provider value={ this.color } ></Provider>// 消費數據/使用數據 <Consumer> { data => <span>--{data} </span>} </Consumer>
  • 場景2 : 動畫插件 react-spring
  • github地址
  • 安裝 : yarn add react-spring
  • 使用 : Render-props api ==> spring
// 引入 import {Spring} from 'react-spring/renderprops'// 使用 ReactDOM.render(<Springconfig={{ duration:4000 }}from={{ opacity: 0 }}to={{ opacity: 1 }}>{props => { console.log(props);return <div style={props}>hello</div>}} </Spring>, document.getElementById('root'))

高階組件的使用

  • render-props 模式 和 高階組件 都是 用來做復用的 : state 和 操作 state 的方法

高階組件介紹

  • 高階組件 : HOC : High-Order Component

  • 實際上就是一個函數, 這個函數能夠接受一個參數組件, 然后,返回一個增強后的組件

  • 參數組件 : 就是需要被包裝的組件

  • 返回的組件 : 增強后的組件, 這個組件中就是通過Props來接收到復用的狀態邏輯的

  • 思想 : 就是組件在增強的過程中, 傳入了一些數據給 組件的 props

const 增強后的組件 = 高階組件(被包裝組件)

高階組件使用演示

  • 高階組件的代碼
// 這就是一個高階組件 // 職責 : 1 提供鼠標位置狀態 2 提供鼠標位置的方法 const withMouse = WrappedComponent => {class Mouse extends React.Component {// 鼠標位置狀態state = {x: 0,y: 0}// 進入頁面時,就綁定事件componentDidMount() {window.addEventListener('mousemove', this.handleMouseMove)}// 鼠標移動的事件處理程序handleMouseMove = e => {this.setState({x: e.clientX,y: e.clientY})}// 移除事件componentWillUnmount() {window.removeEventListener('mousemove', this.handleMouseMove)}render() {return <WrappedComponent {...this.state} />// return <WrappedComponent x={this.state.x} y={this.state.y} />}}return Mouse }

演示1:創建位置組件

//1. 演示1 位置組件 const Position = props => { console.log(props) // 增強之前props是沒有值的return <p>x:{props.x} y:{props.y}</p> }// 如何使用? // 增強后 = withMouse(增強前) HOC_Position = withMouse(Position)// 渲染 ReactDOM.render(<HOC_Position/>, document.getElementById('root'))

演示2 : 創建移動貓組件

//2.演示2 : 移動貓 const Cat = props => {console.log(props);return <img style={{ position:"absolute", left:props.x-64, top:props.y-64 }} src={cat} alt=""/> }// 使用高階組件增強一下 HOC_Cat = withMouse(Cat)// 渲染 ReactDOM.render(<HOC_Cat/>, document.getElementById('root'))

高階組件分析

  • 高階組件名稱 約定 以 with 開頭
  • 指定函數參數,參數應該以大寫字母開頭(作為要被包裝的組件)
  • 在函數內部創建一個類組件,提供復用的狀態邏輯代碼,并返回
  • 在該組件中,渲染參數組件,同時將狀態通過prop傳遞給參數組件
  • 調用該高階組件,傳入要增強的組件,通過返回值拿到增強后的組件,并將其渲染到頁面中
const withMouse = (WrappedComponent) => {class Mouse extends React.Component { ... 省略鼠標位置狀態 和 操作鼠標位置的方法邏輯render() {return <WrappedComponent {...this.state} /> # 核心}}return Mouse }

給高階組件添加displayName (我們自己封裝高階組件)

  • displayName:用于設置 react-dev-tools (瀏覽器中的react插件) 中組件的展示名稱
  • 注意:該屬性僅僅用于設置展示名稱,并不會對組件功能產生影響,所以,如果不想再 react-dev-tools 中進行區分,實際上,可以省略該設置。
  • 演示 : 效果
// 同時渲染多個高階組件的時候 ReactDOM.render(<div><HocPosition/><HocCat/> </div>, document.getElementById('root'))// 在 react-dev-tools 上面顯示的是這樣的 <Mouse>...</Mouse> <Mouse>...</Mouse>// 這樣很不容易區分,所有需要添加displayName
  • 如何 設置 displayName ?
const withMouse = (WrappedComponent) => {class Mouse extends React.Component {... 省略鼠標位置狀態 和 操作鼠標位置的方法邏輯}// 給高階組件設置名稱,將來在 react-dev-tools 工具中,能夠區分到底是哪一個高階組件包裝的組件function getDisplayName(WrappedComponent) { # +return WrappedComponent.displayName || WrappedComponent.name }Mouse.displayName = getDisplayName(WrappedComponent) # +// 如果還想體現出來是高階組價,就加個前綴Mouse.displayName = `WithMouse_${getDisplayName(WrappedComponent)}` # +return Mouse } - 補充: - 先獲取被包裝組件的 displayName ,如果沒有就獲取它的名字,如果再沒有來個默認的最起碼不會報錯或者返回undefined - WrappedComponent.displayName || WrappedComponent.name

給高階組件傳遞屬性 (我們自己封裝高階組件)

  • 問題 : 如果給 高級組件傳屬性, 發現會丟失,
  • 原因 : 高級組件內部給創建的Mouse組件內沒有賦值屬性. 即 高階組件沒有往下傳遞 Props
  • 解決辦法 : 渲染 WrappedComponent時, 將 state 和 this.props 一起傳遞給 Mouse組件
  • 傳遞方法
// 如果多加了屬性 <HocPosition name='jack'/>// 高階組價內部 : const withMouse = (WrappedComponent) => {class Mouse extends React.Component {... 省略鼠標位置狀態 和 操作鼠標位置的方法邏輯render() { // 之前這里只傳遞給包裝組件 state ,并沒有傳遞propsreturn <WrappedComponent {...this.state} {...this.props} /> # ++++}}return Mouse }// 使用 const Position = props => {// 通過 props 就可以獲取到傳遞給高階組件的屬性了// ... 省略其他代碼 }

setState() 的說明

異步更新數據

  • setState() 是異步更新數據的
  • 為什么是異步的 ?
    • 因為 setState() 可能同時被調用多次,如果是同步的話,狀態就會更新多次,
    • 也就是頁面要發生多次渲染,也就是發生多次重繪和重排,這樣的話,會降低應用的性能。
state = { count: 0 } console.log('前 :',this.state.count) // 0 this.setState({count: this.state.count + 1 })// for (var i = 0; i < 1000; i++) {// this.setState({// count: i// })// } console.log('后 :',this.state.count) // 0

setState 的第一種格式 : setState(stateChange, [callback])

  • 格式 : setState( 對象, 回調 )

  • [] : callback 它將在 setState 完成合并并重新渲染組件后執行。

  • 通常,我們建議使用 componentDidUpdate() 來代替此方式。

this.setState({count : this,state.count + 1 },() => {console.log('這個回調函數會在狀態更新后立即執行',this.state.count) })

演示問題

  • 代碼
console.log('前', this.state.count) // 0 // 異步更新 this.setState({count: this.state.count + 1 // 以為是 1 }) // 異步更新 + 獲取 結果 this.setState({count: this.state.count + 1 // 以為是 2},() => {console.log(this.state.count) // 以為是 2 但是結果是1} ) // 兩次更新 發現結果還都是 1 ,
  • 分析
# [] 這種形式的 setState() 也是異步的,并且在同一周期內會對多個 setState 進行批處理。 # [] 后調用的 setState() 將覆蓋同一周期內先調用 setState 的值,因此商品數僅增加一次。 let newObj = Object.assign({}, obj, { age: 20 }, { age: 30 })# [] 如果后續狀態取決于當前狀態,我們建議使用 updater 函數的形式代替:

setState 的第二種格式 : setState(updater, [callback])

  • 格式 : setState(函數式, 回調)
  • 函數式 : 函數里面返回一個對象
// 異步更新 // 這個為什么就可以了, 因為是通過參數獲取的, 是 React 控制 的,,返回的就是上次更新的 this.setState((state, props) => {return {count: state.count + 1 // 拿到最新的 0 + 1 = 1} }) // 異步更新 + 獲取 結果 // 這個為什么就可以了, 因為是通過參數獲取的, 是 React 控制 的,,返回的就是上次更新的 this.setState((state, props) => {return {count: state.count + 1 //拿到最新的1 + 1 = 2}},() => {console.log(this.state.count) // 結果是2} )
  • 簡寫
// 也可以簡寫 this.setState((state) => ({count: state.count + 1 // 以為是 1}))

總結

// 第一種格式 : setState(stateChnage, [callback]) ★setSrare(對象, 回調)// 第二種格式 :setState(updater, [callback]) ★setSrare(函數式, 回調)// 最常用的還是 第一種格式的簡化操作 setState(stateChange) ★★★ this.setState({count : this.state.count + 1 })

{
return {
count: state.count + 1 // 拿到最新的 0 + 1 = 1
}
})
// 異步更新 + 獲取 結果
// 這個為什么就可以了, 因為是通過參數獲取的, 是 React 控制 的,返回的就是上次更新的
this.setState(
(state, props) => {
return {
count: state.count + 1 //拿到最新的1 + 1 = 2
}
},
() => {
console.log(this.state.count) // 結果是2
}
)

- 簡寫```js // 也可以簡寫 this.setState((state) => ({count: state.count + 1 // 以為是 1}))

總結

// 第一種格式 : setState(stateChnage, [callback]) ★setSrare(對象, 回調)// 第二種格式 :setState(updater, [callback]) ★setSrare(函數式, 回調)// 最常用的還是 第一種格式的簡化操作 setState(stateChange) ★★★ this.setState({count : this.state.count + 1 })

總結

以上是生活随笔為你收集整理的React中级学习(第一天)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。