useContext与useReducer整合

138 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情

继上文,当使用provider传递多个值时包裹的样子正所谓是“狼狈不堪”

<ColorContext.Consumer>
      {
          (theme) => {
              return (
                  <FontContext.Consumer>
                      {
                          (font) => {
                              return(
                                    <div >
                                  <p>theme1 color :{theme}</p>
                                  <p>theme1 font :{font}</p>
                                  <Child3  />
                                  <Child4  />
                              </div>
                              )
                          }
                      }
                  </FontContext.Consumer>
              )
          }
      }
  </ColorContext.Consumer>

于是开始想解决办法

  1. 一、使用useContext直接拿到value值
function Child1(){
            //直接拿到ColorContext与FontContext的初始数据
            const theme = useContext(ColorContext) 
            const font = useContext(FontContext)
            return(
                <div>
                //直接可以使用
                    <p>theme1 color :{theme}</p>
                       <p>theme1 font :{font}</p>
                       <Child3  />
                       <Child4  />
                </div>
            )
        }
  1. 将多个数据整合在一个对象中
const ThemeContext = createContext()

设置一个对象,在根组件中为子组件传值:

  const [theme , setTheme] = useState({color:"red",font:"bold"})

把主题传递给子组件

 <ThemeContext.Provider value={theme}>
                            <Child1 />
</ThemeContext.Provider>

在子组件中使用useContext接收对象,并展示数据

function Child1(){
            const theme = useContext(ThemeContext)
            return(
                <div>
                    <p>theme1 color :{theme.color}</p>
                       <p>theme1 font :{theme.font}</p>
                </div>
            )
        }

开始改变数据,抽离出按钮成为单独组件,当点击按钮时更改对象成为新的数据

先在根组件中把改变对象的方法定义好并传递给Setting组件

 let changeTheme = ()=>{
                setTheme({color:"green",font:"猫猫体"})
}
 <Setting changeTheme ={changeTheme} />

在子组件中接收并使用这个方法。

  function Setting (props){
            const {changeTheme} = props
            return(
                <div>
                    <button onClick={changeTheme}>change theme</button>
                </div>
            )
 }
  1. 二、结合useReducer使用----重点
const [state,dispatch] =useReducer(reducer,initState,init惰性初始化)

useReducer有三个参数,我们先来定义第2个参数

let initState = {color:"red",font:"bold"}

定义第一个参数,它是一个函数,规定他来改变state的状态

如果是red则,如果是green则。

 let theme ={red:{color:"red",font:"bold"},green:{color:"green",font:"猫猫体"}}
 function reducer(state,action){
            switch (action) {
                case "red":
                    return {...theme.red}
                case "green":
                    return {...theme.green}
                default:
                   return state
            }
        }

现在将初始状态先展示在根组件中:

 const [theme,dispatch] = useReducer(ThemeReducer,initState)

此时的theme为initState初始数据,直接展示

<p>theme color : {theme.color}</p>
<p>theme font : {theme.font}</p>

再设置一个上下文,将theme与dispatch传入子组件中

 const StateContext = createContext({})

provider包裹,在value中将theme与dispatch传入子组件中

<StateContext.Provider value={{theme,dispatch}}>
                            <Child1 />
                            <Setting  />
</StateContext.Provider>

先来到Setting子组件使用useContext接收

  const {theme,dispatch} = useContext(StateContext)

使用dispatch来改变为green

  <button onClick={()=>{dispatch("green")}}>change theme</button>

再来到子组件中接收provider包裹传来的value值。

  const {theme,dispatch} = useContext(StateContext)
  //使用theme中的数据来展示
   return(
     <div>
         <p>theme1 color :{theme.color}</p>
            <p>theme1 font :{theme.font}</p>
           
     </div>
 )

两个钩子函数结合使用总结流程:

定义init初始数据,定义reducer函数方便来改变数据

来到根组件中使用useReducer接收reducer函数与初始数据参数

将useReducer的返回值[theme,dispatch]通过Provider中的value传递给子组件

子组件使用useContext接收value数据并加以使用