JSX基本使用&React(1)

  1. React元素的屬性名使用駝峰命名法
  2. 特殊屬性名:class -> className for -> htmlFor tabindex -> tabIndex
  3. 沒有子節(jié)點的React元素可以用/>結束
  4. 推薦:使用小括號包裹JSX说墨,從而避免JS中的自動插入分號陷阱
const dv = (
   <div>hello</div>
)
  1. jsx中是使用Javascript表達式
  • 數(shù)據(jù)儲存在JS中
  • 語法:{JavaScript表達式} 注意不是雙大括號析恋!
const name = 'jack'
const dv = (
   <div>你好塘揣,我叫{name}</div>
)

6.條件渲染

// 條件渲染
const isLoading = true
const loadData = () => {
  if(isLoading){
    return <div>loading...</div>
  }
  return <div>數(shù)據(jù)加載完成,此處顯示加載后的數(shù)據(jù)</div>
}

const title = (
  <h1>條件渲染:{loadData()}</h1>
)
ReactDOM.render(title,document.getElementById('root'))

還可以使用if/else三元運算符邏輯與運算符來實現(xiàn)

//三元表達式
const loadData = () => {
  return isLoading ? (<div>loading...</div>) : (<div>數(shù)據(jù)加載完成,此處顯示加載后的數(shù)據(jù)</div>)
}
//邏輯與運算符
const loadData = () => {
  return isLoading && (<div>loading...</div>)
}

isLoading是false不會執(zhí)行后面的,true才會執(zhí)行
7.列表渲染

const songs = [
  {name:'qwe',id:1},
  {name:'dfddg',id:2},
  {name:'hsd',id:3}
]

const title = (
  <ul>
    {songs.map(item => <li key={item.id}>{item.name}</li>)}
  </ul>
)

注意:

  • 列表要渲染一組數(shù)據(jù),應該使用map()方法
  • 列表渲染應該添加key屬性,key屬性的值要保證唯一
  • 原則:map()遍歷誰静檬,就給誰添加key屬性
  • 注意:盡量避免使用索引號作為key,索引號可變不穩(wěn)定

8.JSX樣式處理

    1. 行內(nèi)樣式--style
const list = (
  <h1 style={{color:'red',backgroundColor:'skyblue'}}>
    jsx樣式處理
  </h1>
)
    1. className樣式
//導入
import './index.css'
const list = (
<h1 className="title" style={{color:'red',backgroundColor:'skyblue'}}>
    jsx樣式處理
  </h1>
)
//index.css
.title{
  text-align: center;
}

9.react組件的兩種創(chuàng)建方式

  • 9.1 使用函數(shù)創(chuàng)建組件
  • 使用js函數(shù)或者箭頭函數(shù)創(chuàng)建
  • 函數(shù)名首字母大寫并级,react以此區(qū)分 組件 和普通的 元素
  • 函數(shù)要有return值
  • 渲染函數(shù)組件:用函數(shù)名作為組件標簽名
  • 組件標簽可以是單標簽也可以是雙標簽
function Hello(){
  return(
    <div>我的第一個react組件拂檩!</div>
  )
}
ReactDOM.render(<Hello />,document.getElementById('root'))

箭頭函數(shù)

const Hello = () => <div>我的第一個react組件</div>
  • 9.2 使用類創(chuàng)建組件
    類組件:使用ES6的class創(chuàng)建的組件
    約定1:類名也必須以大寫字母開頭
    約定2:類名稱應該繼承React.Component父類,從而可以使用父類中提供的方法或?qū)傩?br> 約定3:類組件必須提供render()方法
    約定4:render()方法必須有返回值死遭,表示該組件的結構
class Hello extends React.Component{
  render(){
    return(
      <div>我的第一個react類組件广恢!</div>
    )
  }
}

9.3 抽離為獨立的js文件
組件作為獨立的個體,獨立存放一個組件

  • 創(chuàng)建Hello.js文件
  • 在文件中導入react
  • 創(chuàng)建組件
  • 在Hello.js中導出該組件
  • 在index.js中導入該組件
  • 渲染組件

10.點擊事件:駝峰命名法呀潭,

  • 函數(shù)組件綁定事件
// 通過函數(shù)組件綁定事件
function App() {
  function handleClick(){
    console.log('函數(shù)組件中的事件綁定钉迷,事件觸發(fā)了')
  }
  return(
    <button onClick={handleClick}>點我,點我</button>
  )
}
ReactDOM.render(<App />,document.getElementById('root'))
  • 類組件
class  App extends React.Component{
    handleClick(){
        console.log('單擊事件觸發(fā)了')
    }
    render(){
        return(
            <button onClick={this.handleClick}>點我钠署,點我</button>
        )
    }
}
ReactDOM.render(<App />,document.getElementById('root'))

11.事件對象

  • 通過時間處理程序獲取到事件對象
  • react中的事件對象叫做:合成事件(對象)
  • 合成事件:兼容所有瀏覽器糠聪,無需擔心跨瀏覽器兼容性問題

12.有狀態(tài)組件和無狀態(tài)組件

  • 函數(shù)組件又叫做無狀態(tài)組件,類組件又叫做有狀態(tài)組件
  • 狀態(tài)(state)即數(shù)據(jù)
  • 函數(shù)組件沒有自己的狀態(tài)谐鼎,只負責數(shù)據(jù)展示(靜)
  • 類組件有自己的狀態(tài)舰蟆,負責更新UI,讓頁面”動“起來

13.組件中的state和setState

  • 狀態(tài)(state)即數(shù)據(jù)狸棍,是組件內(nèi)部私有數(shù)據(jù)
  • state的值是對象身害,表示一個組件中可以有多個數(shù)據(jù)
  • 狀態(tài)改變,語法:this.setState({要修改的數(shù)據(jù)})草戈,注意塌鸯,不要直接修改state中的值,這是錯誤L破1!
this.setState({
  number: this.number + 1
})
  • setState()作用:1.修改state 2.更新UI
  • 思想:數(shù)據(jù)驅(qū)動視圖

14.抽離onclick的方法费韭,解決this指向問題

  • 1.箭頭函數(shù)茧球,利用箭頭函數(shù)自身不綁定this的特點
class App extends React.Component{
    state = {
        count: 0, 
    }
    onIncrement() {
        this.setState({
            count: this.state.count + 1
        })
    }
    render(){
        return(
        <div>
            <h1>計數(shù)器:{this.state.count}</h1>
//箭頭函數(shù)中的this指向外部環(huán)境,此處為:render()方法
            <button onClick={()=>this.onIncrement()}>+1</button>
        </div>
        ) 
    }
}
  • 2.Function.prototype.bind()
    利用ES5中的bind方法星持,將事件處理程序中的this與組件實例綁定到一起
class App extends React.Component{
    state = {
        count: 0, 
    }
    constructor() {
      super()
      this.onIncrement = this.onIncrement.bind(this)
    }
    onIncrement() {
        this.setState({
            count: this.state.count + 1
        })
    }
    render(){
        return(
        <div>
            <h1>計數(shù)器:{this.state.count}</h1>
//箭頭函數(shù)中的this指向外部環(huán)境抢埋,此處為:render()方法
            <button onClick={this.onIncrement}>+1</button>
        </div>
        ) 
    }
}
  • 3.class實例方法,推薦使用
    利用箭頭函數(shù)形式的class實例方法。注意:該語法是實驗性語法揪垄,但是鲤屡,由于babel的存在可以直接使用
class App extends React.Component{
    state = {
        count: 0, 
    }
    onIncrement = () => {
        this.setState({
            count: this.state.count + 1
        })
    }
    render(){
        return(
        <div>
            <h1>計數(shù)器:{this.state.count}</h1>
            <button onClick={this.onIncrement}>+1</button>
        </div>
        ) 
    }
}

15.表單處理

  • 1.受控組件
    • 由state的值來控制表單元素的值
    • 步驟:
      • 1.在state中添加一個狀態(tài),作為表單元素的value值(控制表單元素值的來源)
      • 2.給表單元素綁定change事件福侈,將表單元素的值設置為state的值(控制表單元素的變化)
class App extends React.Component{
   state = {txt:''}
    handleChange = e => {
        this.setState({
            txt:e.target.value
        })
    }
    render(){
        return(
        <div>
            <input type="text" value={this.state.txt} onChange={this.handleChange}>+1</input>
        </div>
        ) 
    }
}
  • 2.多表單元素優(yōu)化
    • 1.給表單增加name屬性,名稱與state相同
    • 2.根據(jù)表單元素類型獲取對應值
    • 3.在change事件處理程序中通過[name]來修改對應的state
<input name="txt" type="text" value={this.state.txt} onChange={this.handleChange}></input>


//根據(jù)表單元素類型獲取值
const value = target.type === "checkbox"
  ? target.checked
  : target.value

//根據(jù)name設置對應state
this.setState({
  [name]: value
})

  • 3.非受控組件
    借助于ref卢未,使用原生DOM方式來獲取表單元素值
    ref作用:獲取DOM或組件
    使用步驟:
    • 1.調(diào)用React.createRef()方法創(chuàng)建一個ref對象
construction(){
  super()
  this.txtRef = React.reacteRef()
}
    • 2.將創(chuàng)建好的ref對象添加到文本框中
<input type="text" ref={this.txtRef} />
    • 3.通過ref對象獲取到文本框的值
console.log(this.txtRef.current.value)

16.組件的props

  • 組件是封閉的肪凛,要接收外部數(shù)據(jù)應該通過props來實現(xiàn)
  • props的作用:接收傳遞給組件的數(shù)據(jù)
  • 傳遞數(shù)據(jù):給組件標簽添加屬性
  • 接收數(shù)據(jù):函數(shù)組件通過參數(shù)props接收數(shù)據(jù),類組件通過this.props接收數(shù)據(jù)
    父傳子
    特點:
  • 可以給組件傳遞任意類型的數(shù)據(jù)
  • props是只讀的對象辽社,只能讀取屬性的值伟墙,無法修改對象
// 2.接收數(shù)據(jù)
const Hello = (props) => {
    console.log(props)
    props.fn()
    // 修改props的值:錯誤演示!!!!!!!
    // props.name = '123'
    return(
        <div>
            <h1>props:{props.name}</h1>
            {props.tag}
        </div>
    )
}
// 1.傳遞數(shù)據(jù)
ReactDOM.render(<Hello name="jack" age={19} fn={()=>console.log('這是一個函數(shù)')} tag={<p>這是一個p標簽</p>} />,document.getElementById('root'))
// 2.接收數(shù)據(jù)
class Hello extends React.Component{
    constructor(props){
        super(props)
        console.log(props)
        props.fn()
    }
    render(){
        return(
            <div>
                <h1>props:{this.props.age}</h1>
            </div>
        )
    }
}
// 1.傳遞數(shù)據(jù)
ReactDOM.render(<Hello name="rose" age={19} color={['red','green','blue']}  />,document.getElementById('root'))
  • 注意:使用類組件時,如果寫了構造函數(shù)滴铅,應該將props傳遞給super(),否則戳葵,無法在構造函數(shù)constrauctor中獲取到props!
class Hello extends React.Component{
//推薦將props傳遞給父類構=構造函數(shù)
  constrauctor(props){
    super(props)
  }
  render(){
    return (
             <div>
                 <h1>props:{this.props.age}</h1>
             </div>
    )
  }
}

子傳父

    • 1.父組件提供一個回調(diào)函數(shù)(用于接收數(shù)據(jù))
    • 2.自組件調(diào)用傳入的函數(shù)
      兄弟組件傳遞
      狀態(tài)提升汉匙,由兄弟組件共同的父組件管理狀態(tài)
      17.Context
      跨組件傳遞數(shù)據(jù)
      使用步驟:
  • 1.調(diào)用React.createCcontext()創(chuàng)建Provider(提供數(shù)據(jù))和Consumer(消費數(shù)據(jù))兩個組件
const { Provider, Consumer } = React.createContext()
  • 2.使用Provider組件作為父節(jié)點
  • 3.設置value屬性拱烁,表示要傳遞的數(shù)據(jù)
<Provider value="pink">
  • 4.調(diào)用Consumer組件接收數(shù)據(jù)
<Consumer>
  { data => <span>data參數(shù)表示接收到的數(shù)據(jù) -- { data }</span> }
</Consumer>

18.props深入
18.1 children屬性:表示組件標簽的子節(jié)點,當組件標簽有子節(jié)點時噩翠,props就會有該屬性

function Hello (props){
  return(
    <div>
      組件的子節(jié)點:{ props.chihldren }
    </div>
  )
}

< Hello>我是子節(jié)點</Hello>

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

  • 對于組件來說伤锚,props是外來的擅笔,無法保證組件使用者傳入什么格式的數(shù)據(jù)
  • 傳入到的數(shù)據(jù)格式不對,可能會導致報錯
  • 作用:捕獲使用組件時因為props導致的錯誤屯援,給出明確的錯誤提示猛们,增加組件的健壯性
App.propTypes = {
  colors: PropTypes.array
}

使用步驟:

    • 安裝包prop-types(yarn add prop-types/npm i prop-types)
    • 導入prop-types包
import PropTypes from 'prop-types'
    • 使用 組件名.propTypes = {} 來給組件的props添加校驗規(guī)則
      約束規(guī)則:
      1.常見類型:array、bool狞洋、func弯淘、number、object徘铝、string
      2.react元素類型:element
      3.必填項:isRequired
      4.特定結構的對象:shape({})
//添加props校驗
//屬性a的類型 數(shù)值
//屬性fn的類型 函數(shù)并且為必填項
//屬性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
  })
}

18.3 props默認值:未傳入props時生效
App.defaultProps = {
pageSize:0
}

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


      生命周期-掛載.jpg
  • 2.更新階段
    執(zhí)行時機:1.setState() 2.forceUpdate() 3.組件接收到新的props
    說明:以上三者任意一種變化,組件就會重新渲染
    執(zhí)行順序:


    生命周期-更新.jpg

    在componentDidUpdate中調(diào)用this.setState時需要加if條件語句判斷

//比較更新前后的props是否相同淹魄,來決定是否重新渲染組件
if(prevProps.count !== this.props.count){
  this.setState({})
  //或者發(fā)送ajax請求的代碼
}
    1. 卸載階段
      執(zhí)行時機:組件從頁面消失


      生命周期-卸載.jpg
  1. render-props和高階組件
    20.1 React組件復用
    復用什么:1.state 2. 操作state的方法(組件狀態(tài)邏輯)
    兩種方式:1.render props模式 2. 高階組件(HOC)
    1. .render props模式
//調(diào)用
<Mouse render={(mouse)  =>{
... ...
}}></Mouse>

//組件內(nèi)部
render(){
  return this.props.render(this.state)
}

children代替render屬性

//調(diào)用
<Mouse>{() => {
... ...
}}<Mouse>

//組件內(nèi)部
this.props.children(this.state)

組件優(yōu)化:

//添加校驗
Mouse.propsTypes = {
  children: PropTypes.func.isRequired
}

代碼優(yōu)化:
1.給render props模式添加props校驗
2.應該在組件卸載時郁惜,解除mousemove事件綁定

Mouse.propsTypes = {
  children: PropTypes.func.isRequired
}

componentWillUnmount(){
  window.removeEventListener('mousemove',this.handleMouseMove)
}

20.2高階組件
目的:實現(xiàn)狀態(tài)邏輯復用
使用步驟:
1.創(chuàng)建一個函數(shù),名稱約定以with開頭
2.指定函數(shù)參數(shù),參數(shù)應該以大寫字母開頭(作為要渲染的組件)
3在函數(shù)內(nèi)部創(chuàng)建一個類組件兆蕉,提供復用的狀態(tài)邏輯代碼羽戒,并返回
4.在該組件中,渲染參數(shù)組件虎韵,同時將狀態(tài)通過prop傳遞給參數(shù)組件
5.調(diào)用改高階組件易稠,傳入要增強的組件,通過返回值拿到增強后的組件包蓝,并將其渲染到頁面中

function withMouse(WrappedComponent){
  class Mouse extends React.Component {}
  return Mouse
}

//Mouse組件中的render方法
return <WrappedComponent {...this.state} />
//創(chuàng)建高階組件
function withMouse(WrappedComponent){
  //該組件提供復用的狀態(tài)邏輯
  class Mouse extends React.Component{
    state:{
      x:0,
      y:0
    }

    handleMouseMove = e => {
      this.setState({
        x:e.clientX,
        y:e.clientY
      })
    }

    //  控制鼠標狀態(tài)的邏輯
    componentDidMount(){
      window.addEventListener('mousemove',this.handleMouseMove)
    }
    componentWillUnmount(){
      window.removeEventListener('mousemove',this.handleMouseMove)
    }

    render(){
      return <WrappedComponent {...this.state} {...this.props} />
    }
  }
  //設置displayName
  Mouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`

  return Mouse
}

function getDisplayName(WrappedComponent){
  return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}

//用來測試高階組件
const Position = props =>{
   return (
      <p>
        鼠標當前位置:(x:{props.x},y:{props.y})
      </p>
  )

}

//獲取增強后的組件:
const MousePosition = withMouse(Position)

class App extends React.Component{
  render() {
     return(
      <div>
        <h1>高階組件</h1>
        <MousePosition a='1' />
      <div/>
    )
  }
}

設置displayName

  • 使用高階組件存在的問題:得到的兩個組件名稱相同
  • 原因:默認情況下驶社,React使用組件名稱作為displayName
  • 解決方式:為高階組件設置displayName便于調(diào)試時區(qū)分不同的組件
  • displayName的作用:用于設置調(diào)試信息(React Developer Tools信息)
Mouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`

function getDisplayName(WrappedComponent){
  return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}

傳props:

    render(){
      return <WrappedComponent {...this.state} {...this.props} />
    }
    //組件MousePosition 傳入的參數(shù)就不會丟失了

21.setState說明
21.1異步更新
調(diào)用多次setState,只會觸發(fā)一次render渲染
21.2推薦語法

this.setState((state,props)=>{
  return{
    count:state.count + 1
  }
})

回調(diào)函數(shù)形式的setState更新也是異步更新测萎,立刻打印state亡电,結果還是1。
連續(xù)兩次更新state加1硅瞧,第二次是在第一次基礎上加一的份乒,即第二次拿到的值是2,第二次更新是在2上?1
21.3
setState第二個參數(shù)

  • 場景:在狀態(tài)更新(頁面完成重新渲染)后立即執(zhí)行
  • 語法:setState(updater,[,callback])
this.setState(
(state,props)=>{},
()=>{console.log('這個回調(diào)函數(shù)會在狀態(tài)跟新后立即執(zhí)行')}
)
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腕唧,一起剝皮案震驚了整個濱河市或辖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌四苇,老刑警劉巖孝凌,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異月腋,居然都是意外死亡蟀架,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門榆骚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來片拍,“玉大人,你說我怎么就攤上這事妓肢“剖。” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵碉钠,是天一觀的道長纲缓。 經(jīng)常有香客問我,道長喊废,這世上最難降的妖魔是什么祝高? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮污筷,結果婚禮上工闺,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好陆蟆,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布雷厂。 她就那樣靜靜地躺著,像睡著了一般叠殷。 火紅的嫁衣襯著肌膚如雪改鲫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天林束,我揣著相機與錄音钩杰,去河邊找鬼。 笑死诊县,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的措左。 我是一名探鬼主播依痊,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼怎披!你這毒婦竟也來了胸嘁?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤凉逛,失蹤者是張志新(化名)和其女友劉穎性宏,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體状飞,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡毫胜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了诬辈。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酵使。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖焙糟,靈堂內(nèi)的尸體忽然破棺而出口渔,到底是詐尸還是另有隱情,我是刑警寧澤穿撮,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布缺脉,位于F島的核電站,受9級特大地震影響悦穿,放射性物質(zhì)發(fā)生泄漏攻礼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一咧党、第九天 我趴在偏房一處隱蔽的房頂上張望秘蛔。 院中可真熱鬧,春花似錦、人聲如沸深员。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽倦畅。三九已至遮糖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叠赐,已是汗流浹背欲账。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留芭概,地道東北人赛不。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像罢洲,于是被迫代替她去往敵國和親光涂。 傳聞我的和親對象是個殘疾皇子苟跪,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容