React Hooks初探(二)

335 阅读2分钟

hooks引入react里已经很长时间了,在项目中一直使用,文档也没仔细阅读,今天打算再重新看看文档,领略一下当初学习的感受。

这是我参与8月更文挑战的第15天,活动详情查看:8月更文挑战

今天继续学习几个高阶的Hooks:useContextuseCallback

useContext

想象一下这个场景: 你有一个组件,你在里面定义了一些状态和修改状态的方法,该组件里又嵌套了一些子组件。突然有一天该组件的某个重孙子组件需要使用该组件的状态,你可能将不得不把状态相关的属性一直下传到该后代组件。中间组件可能被传入了并不需要的状态或数据,长期下去,可能会让代码变得混乱不堪。

其实,我们只关心两个因素:

  • 状态在哪里?
  • 谁用 其他的问题,定义状态的地方和使用状态的地方相隔了多少组件或嵌套了多深不应该成为困扰开发者的因素。而这正是useContext的设计精髓所在。

用代码来表示:一共三个组件:App->Parent->Child

//context.ts
import React from "react"
interface IUserInfo {
    name?:string,
    age?:number,
    sex?:string
}
export const AppContext = React.createContext<IUserInfo>({})

//App.tsx
import {AppContext} from './app-context'
import {Parent} from './parent'
export const App = ({}) => {
  return <AppContext.Provider value={{
    name:"安德鲁",
    age:18,
    sex:""
  }}>
    <Parent/>
  </AppContext.Provider>
}


//parent.tsx
import React from "react"
import {Child} from './child'
export const Parent:React.FC<{}> = () => {
    return <h2>
        <Child/>
    </h2>
}

//child.tsx
import React from "react"
import {AppContext} from './context'
export const Child:React.FC<{}> = () => {
    const userInfo = React.useContext(AppContext)
    return <h2>
        姓名:{userInfo.name} <br/>
        年龄:{userInfo.age} <br/>
        性别:{userInfo.sex} <br/>
    </h2>
}

看出来了吗?parent组件里并未从App里接收状态并传递给child。而是直接在child里直接通过useContext拿到上层定义的值。

useCallback

开始介绍之前,先考虑一个场景: 父组件里定义了一个方法,然后该方法被props给子组件,然后子组件该props方法更新时渲染(useEffect)。当父组件重新渲染时会发生什么事呢?

//parent.ts
export const Parent:React.FC<{}> = () => {
    const [counter,setCounter] = React.useState(0)
    const [staticState,setStaticState] = React.useState(false)
    useEffect(()=>{
        console.log('parent update')
    })
    //本组件每次渲染时该方法会声明一个新的函数(引用)
    const callback = ()=>{
        console.log('父组件定义了一个函数!')
    }
    //本组件每次渲染时,只有staticState发生改变时才会声明一个新的函数(引用)
    const callback = React.useCallback(
        () => {
        },
        [staticState]
    );
    return <div>
        {counter}
        <button onClick={()=>{ setCounter(counter+1) }}>点击</button>
        <Child callback={callback}/>
    </div>
}
// child.ts
export const Child:React.FC<{callback:any}> = ({callback}) => {
    React.useEffect(()=>{
        console.log('child update')
    },[callback])
    return <h2></h2>
}

我们发现,当父组件重新渲染时,没有使用useCallback时子组件会随着父组件渲染而渲染,当使用useCallback+useEffect时子组件只会在父组件的staticState发生变化时才会重新渲染。

未完待续

感谢阅读!