react建立專案&&常見的三大Hook

淡然置之發表於2024-09-01

react建立專案&&常見的三大Hook

建立react腳手架專案

全域性安裝 create-react-app 工具:

npm i -g create-react-app

檢視安裝工具的版本號,注意V大寫

create-react-app -V

進入要建立的檔案目錄建立react專案,名為:react_project

create-react-app react_project

啟動專案會預設3000埠號開啟瀏覽器

npm start

目錄結構

node_modules/: 存放專案依賴包的目錄。該目錄會在執行 npm install 後生成

public/: 存放公共靜態資原始檔的目錄
    favicon.ico: 瀏覽器標籤上的圖示。
    index.html: 主頁面。
    logo192.png
    log512.png:logo圖
    manifest.json: 應用加殼的配置檔案,定義了應用的圖示、啟動配置、顯示模式等。
    robots.txt:爬蟲協議檔案,控制哪些內容可以被抓取和索引,最佳化搜尋引擎的表現,減少伺服器負擔,並保護網站的敏感資料。
    
src/:原始碼資料夾
    App.css: App 元件的樣式檔案。
    App.js: 主元件檔案,包含應用的主要內容。
    App.test.js: 對 App 元件的測試檔案。
    index.css: 全域性樣式檔案。
    index.js: 應用的入口檔案,將 App 元件渲染到 HTML 檔案中。
    logo.svg: 預設的 React Logo 影像檔案。
    reportWebVitals.js: 用於記錄和報告 Web Vitals 效能指標的檔案。

.gitignore: Git 忽略檔案列表,指定哪些檔案和目錄不應該被版本控制系統跟蹤。

package.json: 專案配置檔案,包含專案的依賴、指令碼和其他後設資料。

README.md: 專案的說明檔案,通常包含專案的介紹、安裝和使用說明。

package-lock.json: 自動生成的檔案,鎖定依賴的版本,以確保專案在不同的環境中安裝一致的版本。

React Hooks

hooks是什麼?

是react 16.8 引入的功能,允許在函式元件中使用state狀態和其他react特性,而無需編寫類元件

三個常用的Hook

  • React.useState()
  • React.useEffect()
  • React.useRef()

useState Hook

用於在函式元件中新增狀態,返回一個狀態變數和一個函式,用於更新這個狀態變數

eg(Components/index.jsx):

類式元件寫法:

import React from 'react'

class Demo extends React.Component {
  state = {count: 0}
  
  add = ()=>{
    this.setState(state => ({count:state.count+1}))
  }
  render () {
    return (
      <div>
        <h1>和為{this.state.count}</h1>
        <button onClick={this.add}>點我加1</button>
      </div>
    )
  }
}

函式式元件寫法:

import React,{useState} from 'react'

function Demo(){
  const [count,setCount] = useState(0)
  const [sex,setSex] = useState('女')
  const [name,setName] = useState('小白')
  
  function add(){
    // console.log('點選');
    // setCount(count+1) //第一種寫法
    setCount(count => count+1) //第二種
  }
  function changeSex(){
    setSex(sex => (sex === '男'? '女': '男'))
  }
  function changeName(){
    setName(name => name="小黑")
  }
    return (
      <div>
        <h1>和為:{count}</h1>
        <h2>我是:{name}</h2>
        <h2>性別:{sex}</h2>
        <button onClick={add}>點我加1</button>
        <button onClick={changeName}>點我改姓名</button>
        <button onClick={changeSex}>點我改性別</button>
      </div>
    )
}

export default Demo

上述程式碼中useState(initialState):

  • useState是一個函式,他接受一個初始狀態initialState作為引數
  • 返回一個陣列,陣列第一個元素是當前的狀態值,第二個元素是一個函式,用於更新狀態

setXXX()兩種寫法:

  • setXXX(newValue):引數為非函式值,直接指定新的狀態值,內部用其覆蓋原來的狀態值
  • setXXX(value => newValue):引數為函式,接收原來的狀態值,返回新的狀態值,內部用其覆蓋原來的狀態值

useEffect Hook

用於處理副作用操作(資料獲取、訂閱、手動操作DOM等)。允許在函式元件中執行這些副作用操作,而不需要使用類元件的生命週期。

  • 類式元件寫法:
import React from 'react'
import ReactDOM from 'react-dom'
import root from '../../index'

// 類式元件
class Demo extends React.Component {
  state = {count: 0}  
  add = ()=>{
    this.setState(state => ({count:state.count+1}))
  }
  unmount = ()=>{
    if(root){
      root.unmount()
    }
  }
  componentDidMount(){
    // console.log('元件掛載完成')
    this.timer = setInterval(()=>{
      this.setState(state => ({count:state.count+1}))
    },1000)
  }
  componentWillUnmount(){
    // console.log('元件將要解除安裝')
    clearInterval(this.timer)
  }
  render () {
    return (
      <div>
        <h1>和為{this.state.count}</h1>
        <button onClick={this.add}>點我加1</button>
        <button onClick={this.unmount}>解除安裝</button>
      </div>
    )
  }
}
export default Demo
  • 函式式元件寫法:
import React,{useEffect,useState} from 'react'
import ReactDOM from 'react-dom'
import root from '../../index'


function Demo(){
  const [count,setCount] = useState(0)
  
  // useEffect(()=>{
  //   console.log('-----');    
  // },[count])
/*   
  注意:上面的空陣列,表示誰也不監測。
  不寫的話就是全都監測(元件掛載和更新都會監測到)
  具體監測到什麼就寫什麼,比如[count] 就只監測count
   */
  useEffect(()=>{
    let timer = setInterval(()=>{
      setCount(count => count+1)
    },3000)
    return ()=>{
      clearInterval(timer)
    }
  },[])
  function add(){
    setCount(count => count+1)
  }
  function onmount(){
    if(root){
      root.unmount();
    }
  }
  return (
    <div>
      <h1>和為:{count}</h1>
      <button onClick={add}>點我加1</button>
      <button onClick={onmount}>解除安裝</button>
    </div>
  )
}
export default Demo

useRef Hook

類式元件寫法:

import React from 'react'
import root from '../../index'

// 類式元件
class Demo extends React.Component {
  state = {count: 0}  
  myRef = React.createRef()
  add = ()=>{
    this.setState(state => ({count:state.count+1}))
  }
  show = ()=>{
    alert(this.myRef.current.value)
  }
  unmount = ()=>{
    if(root){
      root.unmount()
    }
  }
  componentDidMount(){
    // console.log('元件掛載完成')
    this.timer = setInterval(()=>{
      this.setState(state => ({count:state.count+1}))
    },1000)
  }
  componentWillUnmount(){
    // console.log('元件將要解除安裝')
    clearInterval(this.timer)
  }
  render () {
    return (
      <div>
        <h1>和為{this.state.count}</h1>
        <input type="text" ref= {this.myRef} />
        <button onClick={this.add}>點我加1</button>
        <button onClick={this.unmount}>解除安裝</button>
        <button onClick={this.show}>彈窗顯示資料</button>
      </div>
    )
  }
}

函式式元件寫法:

import React,{useState,useEffect,useRef} from 'react'
import root from '../../index'

function Demo(){
  const [count,setCount] = useState(0)
  const myRef = useRef()

  useEffect(()=>{
    let timer = setInterval(()=>{
      setCount(count => count+1)
    },3000)
    return ()=>{
      clearInterval(timer)
    }
  },[])
  function add(){
    setCount(count => count+1)
  }
  function onmount(){
    if(root){
      root.unmount();
    }
  }
  function show (){
    alert(myRef.current.value)
  }
  return (
    <div>
      <h1>和為:{count}</h1>
      <input type="text" ref = {myRef} />
      <button onClick={add}>點我加1</button>
      <button onClick={onmount}>解除安裝</button>
      <button onClick={show}>點我顯示輸入框資訊彈窗</button>
    </div>
  )
}

export default Demo

遇到的問題:

問題1:useEffect生命週期函式為什麼會被進行兩次呼叫?

問題分析:

這部分程式碼,我看到控制檯--------列印了兩次,其原因是react的嚴格模式會在開發環境下對某些生命週期函式(包括useEffect)進行兩次呼叫,這是為了驗證副作用的影響,生產模式不會發生這種情況

解決方法:

在indedx.js入口檔案中,刪除或者註釋掉React.StrictMode即可

問題2:react元件解除安裝報錯問題,如下:
報錯顯示及分析:
  • unmountComponentAtNode is deprecated and will be removed in the next major release. 報錯提示是因為unmountComponentAtNode已經被棄用
  • You are calling ReactDOM.unmountComponentAtNode() on a container that was previously passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()?嘗試用舊的解除安裝方法 ReactDOM.unmountComponentAtNode() 去解除安裝一個之前使用新的 ReactDOM.createRoot() 方法建立的 React 根節點。這兩者是不相容的。
  • unmountComponentAtNode(): The node you're attempting to unmount was rendered by React and is not a top-level container. Instead, have the parent component update its state and rerender in order to remove this component.你試圖解除安裝的節點不是一個頂層容器節點。換句話說,你可能在試圖解除安裝由 React 管理的子元件,而不是根節點。
解決方法:

透過將root匯出並在其他地方匯入來管理解除安裝元件,這是因為直接管理root物件是因為它提供了對react根結點更好的控制,尤其是在react18及以上版本時。他確保能正確地解除安裝和管理元件,而不會引發錯誤或與舊版本產生衝突

操作步驟:
  • 在入口檔案index.js匯出root:
export default root;
  • 在要解除安裝的元件檔案中匯入root:
import root from '../../index' //根據自己路徑調整

  function onmount(){
    if(root){
      root.unmount();
    }
  }

<button onClick={onmount}>解除安裝</button>

相關文章