useRef
import React,{useRef,useState} from 'react'
export default function App() { const myText = useRef('初始默认值') const [content,setContent] = useState('') return ( <div> {/* 通过useRef设置ref属性 */} <input ref={myText}/>
<button onClick={()=>{ // 通过 ref 属性获取到输入框的数据 console.log('输入框的数据库为:',myText.current.value) setContent(myText.current.value)//将数据更新到state中 myText.current.value = ''//清空输入框! }}>add</button>
<p>state状态:{content}</p> </div> ) }
|
useContext
官方文档
函数式组件中的useContext
我们可以认为是类组件中的Context
,都是用于跨组件间通信的,同时可将其类比为vue
中的事件总线
,它设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。使用 context, 我们可以避免通过中间元素传递 props。
在函数式组件中使用useContext
实现跨级组件间的通信同样要结合createContext
来使用,首先使用createContext
来创建全局事件总线
,随后使用.Provider
来指定消息的提供方, 再在其他组件中使用useContext()
来获取消息提供方的数据,最后直接调用即可,不需要使用.Consumer
来包裹调用!
代码展示;
import React, { useState, createContext, useContext } from 'react'
const myData = createContext(0)
const Sun = () => { var {num,addNum} = useContext(myData) console.log(useContext(myData)); return ( <div> <p>---------------- 孙组件 ------------------</p> {/* 直接使用结构出来的数据和方法即可 */} <p>父组件中获取到的数据;{num}</p> <button onClick={addNum}>点击父组件中的数据+1</button> </div> ) }
const Son = () => { return ( <div> <p>---------------- 子组件 ------------------</p> <p>作为中间人将孙组件和父组件间隔为跨级组件</p> <Sun></Sun> </div> ) }
export default function Father() { const [num,setnum] = useState(0) const addNum = ()=>{ setnum(num+1) } return ( <myData.Provider value={{num,addNum}}> <div> <p>---------------- 父组件 ------------------</p> <p>state中的数据:{num}</p> <Son></Son> </div> </myData.Provider> ) }
|
结果展示:
useReducer
官方文档
useReducer
是 useState
的替代方案。它接收一个形如 (state, action) => newState 的 reducer
,并返回当前的 state 以及与其配套的 dispatch
方法。对比之下,useState
是将状态保存到组件内部,而useReducer
则是将状态提取到所有组件之外共同管理,在结合useContext
的使用后基本可以作为Redux
来使用,就类似于Vue
中的Vuex
Reducer
- 为了更好的理解
useReducer
,所以先要了解JavaScript
里的Redcuer
是什么。它的兴起是从Redux
广泛使用开始的,但不仅仅存在Redux
中,可以使用原生的JavaScript来完成Reducer
操作。所谓reducer
其实就是一个函数,这个函数接收两个参数,一个是状态,一个用来控制业务逻辑的判断参数。我们举一个最简单的例子。
function countReducer(state, action) { switch(action.type) { case 'add': return state + 1; case 'sub': return state - 1; default: return state; } }
|
上面的代码就是Reducer
,你主要理解的就是这种形式和两个参数的作用,一个参数是状态,一个参数是如何控制状态。
useReducer
结合useContext
实现类似redux
- 案例需求: 创建全局变量(
state
)和修改全局变量的唯一方法(reducer
), 创建一个全局的父组件(相当于项目中的app组件
),在这个父组件管辖下有三个子组件,第一个子组件用于展示数据的修改按钮,第二和第三个子组件则用于展示数据。也就是说这个Demo
中有两个按钮,点击第按钮能够修改全局状态中对应的数据。
import React,{useReducer,useContext} from 'react'
const initailState = { name:"lam", age:19 }
const reducer = (prevState,action)=>{ console.log('旧状态',prevState); console.log('对应的处理字段以及新的state参数',action);
let newstate = {...prevState} switch(action.type){ case "changeName": newstate.name = action.value return newstate case "addAge": newstate.age = action.value return newstate default: return prevState } }
const GlobalContext = React.createContext()
export default function App() { const [state, dispatch] = useReducer(reducer, initailState) console.log('全局状态',state); return ( <GlobalContext.Provider value={{state,dispatch}}> <div> <Child1/> <Child2/> <Child3/> </div> </GlobalContext.Provider> ) }
function Child1(){ const {dispatch,state} = useContext(GlobalContext) console.log('当前年龄为',state.age);
return <div style={{background:"pink"}}> <button onClick={()=>{ /* 6. 子组件使用dispatch方法修改全局状态,dispatch传入一个对象, 里面必须要有唯一字段用于指定后续的状态覆盖,以及新的状态数据 */ dispatch({ type:"changeName",//指定唯一字段必传项 value:"肥林",//新的状态数据 }) }}>修改姓名</button>
<button onClick={()=>{ dispatch({ type:"addAge", value:state.age+1 }) }}>+年龄</button> </div> }
function Child2(){ const {state} = useContext(GlobalContext) return <div style={{background:"skyblue"}}> {/* 7. 子组件通过state来获取全局状态数据并展示 */} 姓名-{state.name} </div> }
function Child3(){ const {state} = useContext(GlobalContext) return <div style={{background:"yellowgreen"}}> 年龄-{state.age} </div> }
|
结果展示:
自定义hooks
官方文档
所谓自定义hooks
我们可以简单的认为就是函数的封装
,但是这个函数的名字必须以use
为开头,否则就不能使用React
中的各种hooks
,这个函数(你自定义的hooks
)在形式上和普通函数没有区别,你可以传递任意参数给这个Hooks。但是要注意,Hooks和普通函数在语义化上是由区别的,就在于函数没有用到其他Hooks。什么意思呢?就是说如果你创建了一个 useXXX 的函数,但是内部并没有用任何其它 Hooks,那么这个函数就不是一个 Hook,而只是一个普通的函数。但是如果用了其它 Hooks ,那么它就是一个 Hook。
案例展示:
- 我自定义一个计算机
hooks
,里面有加法,减法,复位以及输出结果
import React,{useState, useCallback} from 'react'
function useCounter() {
const [count, setCount] = useState(0); const increment = useCallback(() => setCount(count + 1), [count]); const decrement = useCallback(() => setCount(count - 1), [count]); const reset = useCallback(() => setCount(0), []); return { count, increment, decrement, reset }; }
export default function App() { const { count, increment, decrement, reset } = useCounter(); return ( <div> <p>结果: {count}</p> <button onClick={increment}> +1 </button> <button onClick={decrement}> -1 </button> <button onClick={reset}> 复位 </button> </div> ) }
|
结果展示: