react中函數(shù)式組件React Hooks詳解
React Hooks
函數(shù)式組件
使用hooks理由
- 高階組件為了復(fù)用,導(dǎo)致代碼層級復(fù)雜
- 生命周期的復(fù)雜
- 寫成functional組件,無狀態(tài)組件,因為需要狀態(tài),又改成了class,成本高
在16.8版本之前函數(shù)式組件無法寫狀態(tài)所以一般只能用class組件成本比較高代碼嵌套比較深,并且鉤子函數(shù)(生命周期相對來說過于復(fù)雜)在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),并且進(jìn)行修改了
// 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ù)式組件的傳值呢通信呢?沒有類組件的寫法這些應(yīng)該怎么寫呢?
請隨我繼續(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
這種方法較為復(fù)雜需要利用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
需要注意學(xué)習(xí)的地方
- input框value值獲取
- 怎么讓進(jìn)行添加
- 怎么讓添加完成后輸入框的value值清空
- 怎么進(jìn)行刪除
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ù)相當(dāng)于一旦創(chuàng)建就會執(zhí)行。
- 如果第二個參數(shù)傳入的依賴狀態(tài)改變也會自動執(zhí)行
- 如果第二個參數(shù)傳入的依賴狀態(tài)為空就相當(dāng)于值會走一次
- 如果不傳任何狀態(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ù)組相當(dāng)于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
在實際應(yīng)用中函數(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
防止因為組件重新渲染,導(dǎo)致方法被重新創(chuàng)建 ,起到緩存作用; 只有第二個參數(shù) 變化了,才重新聲明一次
也就是只需要當(dāng)需要某個狀態(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ù)式組件中進(jìn)行非父子通信的
首先需要創(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) 其實相當(dāng)于一個數(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": //深復(fù)制老狀態(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實現(xiàn)一個簡單的待辦任務(wù)列表
這篇文章主要給大家介紹了使用React和Ant Design庫構(gòu)建的待辦任務(wù)列表應(yīng)用,它包含了可編輯的表格,用戶可以添加、編輯和完成任務(wù),以及保存任務(wù)列表數(shù)據(jù)到本地存儲,文中有相關(guān)的代碼示例,需要的朋友可以參考下2023-08-08React?Hook中的useState函數(shù)的詳細(xì)解析
Hook 就是 JavaScript 函數(shù),這個函數(shù)可以幫助你鉤入(hook into) React State以及生命周期等特性,這篇文章主要介紹了React?Hook?useState函數(shù)的詳細(xì)解析的相關(guān)資料,需要的朋友可以參考下2022-10-10