Skip to content

useContext函数

通常来说,你会通过props将信息从父组件传递到子组件。但是,如果你必须通过许多中间组件向下传递props,或是在你应用中的许多组件需要相同的信息,传递props会变的十分冗长和不便。
Context允许父组件向其下层无论多深的任何组件提供信息,而无需通过props显式传递。

1. 多层组件传递数据

jsx
import { createContext, useContext, useState } from 'react'

function Title() {
  const value = useContext(Context)
  return (
    <div>
      <h3>Title组件</h3>
      {value}
    </div>
  )
}

function Head() {
  return (
    <>
      <h3>Head组件</h3>
      <Title/>
    </>
  )
}
// Context一定要使用大写,设置默认值
const Context = createContext(1)

function App() {
  const [num, setNum] = useState(0)
  const clickHandle = () => {
    setNum(num+1)
  }
  return (
    <div>
      <button onClick={clickHandle}>添加</button>
      <Context.Provider value={num}>
        <Head/>
      </Context.Provider>
    </div>
  )
}

export default App

运行效果:
Alt text 如果传多个值,可以设置为数组或者对象来传递。

2. 共享状态

Reducer可以整合组件的状态更新逻辑。Context可以将信息深入传递给其他组件。你可以组合使用它们来共同管理一个复杂页面的状态。也就是说前面的案例是爷孙组件进行数据通信,兄弟通信就需要共享状态。更复杂的状态管理,可以采用第三方库:Redux,Mobx,Zustand等

jsx
import ListContent from './ListContent.jsx'
import ListHead from './ListHead.jsx'
import ListProvider from './ListProvider.jsx'

function App() {

  return (
    <div>
      <ListProvider >
        <ListHead/>
        <ListContent/>
      </ListProvider>
    </div>
  )
}
export default App
jsx
import {ListContext, ListDispatchContext} from './ListProvider.jsx'
import { useContext } from 'react'

function ListContent() {
  const dataList = useContext(ListContext)
  const listDispatch = useContext(ListDispatchContext)
  return (
    <div>
      <ul>
        {
          dataList.map(item => {
            return (
              <li key={item.id}>
                {item.name}
                <button onClick={()=>listDispatch({type:'edit', id: item.id})}>修改</button>
                <button onClick={()=>listDispatch({type:'remove', id: item.id})}>删除</button>
              </li>
            )
          })
        }
      </ul>
    </div>
  )
}
export default ListContent;
jsx
import {ListDispatchContext} from './ListProvider.jsx'
import { useContext } from 'react'

function ListHead() {
  const listDispatch = useContext(ListDispatchContext)
  return (
    <div>
      <button onClick={() => listDispatch({type: 'add'})} >添加1</button>
    </div>
  )
}

export default ListHead
jsx
import {useReducer, createContext}  from 'react'
import { useImmerReducer } from 'use-immer'

export const ListContext = createContext()
export const ListDispatchContext = createContext()

function listReducer(draft, action) {
  // 其中action就是传值
  switch (action.type) {
    case 'add':
      draft.push({id:5, name:'baden'})
      break
    case 'remove':
      const data = draft.find(item => item.id === action.id)
      draft.splice(data, 1)
      break
    case 'edit':
      const editData = draft.find(item => item.id === action.id)
      editData.name = 'new'+editData.name
      break
  }
}


function ListProvider({children}) {
  const [list, listDispatch] = useImmerReducer(listReducer, [
    { id: 1, name: 'John' },
    { id: 2, name: 'Bob' },
    { id: 3, name: 'Mark' },
    { id: 4, name: 'Trump' }
  ])
  return (
    <ListContext.Provider value={list}>
      <ListDispatchContext.Provider value={listDispatch}>
        {children}
      </ListDispatchContext.Provider>
    </ListContext.Provider>
  )
}

export default ListProvider

运行效果:
Alt text