react中函數(shù)式組件React Hooks詳解
React Hooks
函數(shù)式組件
使用hooks理由
- 高階組件為了復用,導致代碼層級復雜
- 生命周期的復雜
- 寫成functional組件,無狀態(tài)組件,因為需要狀態(tài),又改成了class,成本高
在16.8版本之前函數(shù)式組件無法寫狀態(tài)所以一般只能用class組件成本比較高代碼嵌套比較深,并且鉤子函數(shù)(生命周期相對來說過于復雜)在16.8之后出了函數(shù)式組件的狀態(tài)后,很好的解決了這些弊端。
useState
在之前版本中函數(shù)式組件是不支持狀態(tài)的為了讓函數(shù)式組件更好的支持狀態(tài),可以利用useState
const [name,setName] = useState("Riven")主要利用這個useState的方法 也是一個數(shù)組它有個值一個是Riven,另一個是修改這個狀態(tài)的方法f()你可以打印一下自己查看console.log(useState(“Riven”)) 如上代碼就是將這個狀態(tài)和這個修改狀態(tài)的方法給解構(gòu)出來這樣就可以訪問到狀態(tài),并且進行修改了
// rcc => react component class
// rfc => react component function
import React,{useState} from 'react'
//利用useState讓函數(shù)式組件支持狀態(tài)
function App(){
console.log(useState("Riven"));
//不支持狀態(tài)
const [name,setName] = useState("Riven")
const [age,setAge] = useState(25)
return(
<div>
app----{name}---{age}
<button onClick={()=>{
setName("kerwin")
setAge(100)
}}>click</button>
</div>
)
}
export default App
以上就是函數(shù)式組件的基本寫法了你肯定有許多問題?函數(shù)式組件的生命周期呢?函數(shù)式組件的傳值呢通信呢?沒有類組件的寫法這些應該怎么寫呢?
請隨我繼續(xù)往后看
todolist小案例(函數(shù)式組件)
首先怎么獲取input框中的value值呢?
這里我們有兩種方法和類組件差不多
- 就是利用onChage事件
import React,{useState} from 'react'
function App(){
const [text, setText] = useState("")
return(
<div>
<input type="text" onChange={(ev)=>{
// console.log(ev.target)
setText(ev.target.value)
}} />
</div>
)
}
export default App
- 利用ref
這種方法較為復雜需要利用useRef
import React,{useState,useRef} from 'react'
const mytext = useRef(null)
<input type="text" onChange={(ev)=>{
// console.log(ev.target)
setText(ev.target.value)
}} ref={mytext} />
訪問的時候可以直接通過mytext.current.value得到value值
import React,{useState,useRef} from 'react'
function App(){
const [text, setText] = useState("")
const mytext = useRef(null)
return(
<div>
<input type="text" onChange={(ev)=>{
// console.log(ev.target)
setText(ev.target.value)
}} ref={mytext} />
<button onClick={()=>{
console.log(mytext.current.value)
}}>add</button>
</div>
)
}
export default App
完整的todolist
需要注意學習的地方
- input框value值獲取
- 怎么讓進行添加
- 怎么讓添加完成后輸入框的value值清空
- 怎么進行刪除
import React,{useState,useRef} from 'react'
function App(){
const [text, setText] = useState("")
const [list,setList] = useState(["111","222","333"])
const mytext = useRef(null)
//刪除函數(shù)只是想寫在外面
const handledelclick = (index)=>{
var newlist = [...list]
newlist.splice(index,1)
setList(newlist)
}
return(
<div>
<input type="text" onChange={(ev)=>{
// console.log(ev.target)
setText(ev.target.value)
}} ref={mytext} value={text} />
<button onClick={()=>{
// console.log(mytext.current.value) //ref
setList([...list,text]) //添加數(shù)組
setText(" ")
}}>add</button>
{
list.map((item,index)=>
<li key={item}>
{item}
<button onClick={()=>handledelclick(index)}>del</button>
</li>
)
}
</div>
)
}
export default App
useEffect
在函數(shù)式組件中我們沒有生命周期useEffect類似生命周期但不是生命周期
我們把數(shù)據(jù)請求放在函數(shù)組件的哪里呢?
- 首先需要知道useEffect接收兩個參數(shù),第一個是處理函數(shù),第二是依賴
- 第一個參數(shù)相當于一旦創(chuàng)建就會執(zhí)行。
- 如果第二個參數(shù)傳入的依賴狀態(tài)改變也會自動執(zhí)行
- 如果第二個參數(shù)傳入的依賴狀態(tài)為空就相當于值會走一次
- 如果不傳任何狀態(tài)改變都會觸發(fā)第一個處理函數(shù)的執(zhí)行
- return 出來的這個函數(shù)只有銷毀的時候才會執(zhí)行
useEffect(()=>{
console.log("創(chuàng)建");
var id = setInterval(()=>{
console.log(111);
},2000)
return ()=>{
console.log("銷毀")
clearInterval(id)
}
},[])
下來看一個簡單的案例
import React,{useState,useEffect} from 'react'
const Child = ()=>{
useEffect(()=>{
console.log("創(chuàng)建");
var id = setInterval(()=>{
console.log(111);
},2000)
return ()=>{
console.log("銷毀")
clearInterval(id)
}
},[])
return(
<div>
Child
</div>
)
}
const App = ()=>{
//useEffect(處理函數(shù),[依賴])
const [text, setText] = useState("1111")
const [age, setAge] = useState(25)
// useEffect(()=>{
// console.log("創(chuàng)建或者更新的時候執(zhí)行")
// },[text])
//傳入空數(shù)組相當于cdm
//[text] 只有text的改變才會執(zhí)行一次
//第二參數(shù)不傳表示任何狀態(tài)改變都會重新執(zhí)行
return(
<div>
App ----{text}
<button onClick={()=>{
setText("22222")
}}>click-text</button>
<br/>
{age}
<button onClick={()=>{
setAge(100)
}}>click-age</button>
{
age===25?
<Child/>:
null
}
</div>
)
}
export default App
在實際應用中函數(shù)式組件會自動傳一個參數(shù)props 這樣我們就可以訪問到props里面的屬性了
props.match.params.myid props.history.goBack()
import React,{useState,useEffect} from 'react'
import { PageHeader} from 'antd';
import axios from 'axios'
const Preview = (props)=>{
const [title, settitle] = useState("")
const [content, setcontent] = useState("")
const [category, setcategory] = useState([])
useEffect(()=>{
axios.get(`http://localhost:8000/articles/${props.match.params.myid}`).then(res=>{
console.log(res.data)
let {title,content,category} = res.data
settitle(title)
setcontent(content)
setcategory(category)
})
},[props])
return (
<div>
<PageHeader
className="site-page-header"
onBack={() => {
// console.log("back",this.props.history)
props.history.goBack()//返回上一個頁面
}} //返回按鈕
title={title}
subTitle={category.join("/")}
/>
<div style={{ padding: "24px" }} dangerouslySetInnerHTML={{
__html:content
}}></div>
</div>
)
}
export default Preview
useCallback
防止因為組件重新渲染,導致方法被重新創(chuàng)建 ,起到緩存作用; 只有第二個參數(shù) 變化了,才重新聲明一次
也就是只需要當需要某個狀態(tài)改變的時候才讓函數(shù)執(zhí)行一次
import React,{useState,useCallback} from 'react'
export default function App() {
const [text,settext] = useState("1111")
const test = useCallback(
() => {
console.log(text)
},
[text],
)
test()
return (
<div>
App-{text}
<button onClick={()=>{
settext("22222")
}}>click</button>
</div>
)
}
useContext useReducer
首先這兩個都是用來在函數(shù)式組件中進行非父子通信的
首先需要創(chuàng)建一個GlobalContext 用來包裹這些生產(chǎn)者的
import React from 'react' const GlobalContext = React.createContext() export default GlobalContext
然后引入
import GlobalContext from './store'
總體代碼如下
import React,{useReducer,useContext} from 'react'
import GlobalContext from './store'
import reducer from './store/reducer'
import axios from 'axios'
const Child1 = ()=>{
// useContext(GlobalContext)
// console.log(useContext(GlobalContext))
let {state,dispatch} = useContext(GlobalContext)
return (
<div>
child1-----{state.text}
<button onClick={()=>{
dispatch({
type:"Change_text",
payload:"child11111111111"
})
}}>click</button>
</div>
)
}
const Child2 = ()=>{
let {state,dispatch} = useContext(GlobalContext)
return (
<div>
Child2----{state.text}
<button onClick={()=>{
axios.get("http://localhost:8000/rights").then(res=>{
// console.log(res.data)
dispatch({
type:"Change_list",
payload:res.data
})
})
}}>異步數(shù)據(jù)</button>
{
state.list.map(item=>
<li key={item.id}>{item.title}</li>
)
}
</div>
)
}
const App = ()=>{
const [state,dispatch] = useReducer(reducer,{
isShow:true,
list:[],
text:"我是公共的狀態(tài)"
}) //[公共的狀態(tài),改變公共狀態(tài)的方法]
return (
<GlobalContext.Provider value={{
state,
dispatch
}}>
<Child1/>
<Child2/>
</GlobalContext.Provider>
)
}
export default App這里需要注意
const [state,dispatch] = useReducer(reducer,{
isShow:true,
list:[],
text:"我是公共的狀態(tài)"
}) //[公共的狀態(tài),改變公共狀態(tài)的方法]
這塊useReducer(reducer) 其實相當于一個數(shù)組里面有兩個值一個是公共的狀態(tài)另外一個改變公共狀態(tài)的方法
訪問的時候可以通過usecontext(GlobalContext) 里面有兩個值一個為state,一個為dispatch
const Child1 = ()=>{
// useContext(GlobalContext)
// console.log(useContext(GlobalContext))
let {state,dispatch} = useContext(GlobalContext)
return (
<div>
child1-----{state.text}
<button onClick={()=>{
dispatch({
type:"Change_text",
payload:"child11111111111"
})
}}>click</button>
</div>
)
}異步也差不多
const Child2 = ()=>{
let {state,dispatch} = useContext(GlobalContext)
return (
<div>
Child2----{state.text}
<button onClick={()=>{
axios.get("http://localhost:8000/rights").then(res=>{
// console.log(res.data)
dispatch({
type:"Change_list",
payload:res.data
})
})
}}>異步數(shù)據(jù)</button>
{
state.list.map(item=>
<li key={item.id}>{item.title}</li>
)
}
</div>
)
}
reducer文件
const reducer = (prevstate,action)=>{
let {type,payload} = action
switch(type){
case "Change_text":
//深復制老狀態(tài),返回新狀態(tài)
// prevstate.text
// var newstate = {...prevstate}
return {
...prevstate,
text:payload
} // immutable
case "Change_list":
return {
...prevstate,
list:payload
}
default:
return prevstate
}
}
export default reducer函數(shù)式組件的父子通信問題
這個和類組件差不多,只不過是函數(shù)式組件會自動傳一個參數(shù)props這樣就可以直接訪問到props里面的屬性了
- 父傳子(屬性)
- 子傳父(回調(diào)函數(shù))
// 父子通信 ,靠屬性
// 父->子 , 屬性
// 子->父 , callback( 屬性傳過去一個回調(diào)函數(shù))
import React,{useState} from 'react'
const Navbar = (props)=>{
console.log(props)
return <div>
navbar-{props.myname}
<button onClick={()=>{
props.onEvent()
}}>click</button>
</div>
}
const Sidebar = ()=>{
return <div>
Sidebar
<ul>
<li>111111</li>
<li>222222</li>
<li>333333</li>
</ul>
</div>
}
const Child = (props)=>{
return <div>
child --{props.children}
</div>
}
export default function App() {
const [show, setshow] = useState(false)
return (
<div>
<Navbar myname="測試的抽屜" onEvent={()=>{
console.log("父組件中調(diào)用")
setshow(!show)
}}/>
{
show?
<Sidebar/>
:null
}
<Child>
<div>child-11111111</div>
<div>child-22222222</div>
</Child>
</div>
)
}
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
React避坑指南之useEffect 依賴引用類型問題分析
這篇文章主要介紹了React避坑指南之useEffect 依賴引用類型問題分析,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
react使用useState修改對象或者數(shù)組的值無法改變視圖的問題
這篇文章主要介紹了react使用useState修改對象或者數(shù)組的值無法改變視圖的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
React組件如何優(yōu)雅地處理異步數(shù)據(jù)詳解
這篇文章主要為大家介紹了React組件如何優(yōu)雅地處理異步數(shù)據(jù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10
React18的useEffect執(zhí)行兩次如何應對
這篇文章主要給大家介紹了關(guān)于React18的useEffect執(zhí)行兩次如何應對的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家學習或者使用React具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07
封裝一個最簡單ErrorBoundary組件處理react異常
這篇文章主要介紹了一個處理react異常的ErrorBoundary組件,簡單實用,代碼詳細,對這個組件感興趣的朋友可以參考下2021-04-04
react如何實現(xiàn)側(cè)邊欄聯(lián)動頭部導航欄效果
這篇文章主要介紹了react如何實現(xiàn)側(cè)邊欄聯(lián)動頭部導航欄效果,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03

