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>