react组件化通信-ContextApi的使用细节
常见问题
-
context现在不常见了,不建议使用?
现在的开发,context不常见是对的,但是不是不建议使用,存在即合理,如redux源码就是有用到这个思想的,react-router也是有用到的
但是尽量少用是真的,因为消耗的性能是相对比较大的,因为一旦改变所有的有使用的子组件都会进行渲染更新,这个还是相对比较消耗性能的,所以要慎重!并不是不用
-
context与redux
redux主要做的是数据共享,而context目标的跨层级传递
context涉及到祖孙组件的关系,而redux不涉及这个,组件之间没有明显的层级关系
contextAPI
context的定义就是组件跨层级通讯,思想是有生产者和消费者的概念,生产者定义传递给子组件的数据,子组件作为消费者只要根据指定的设置
contextType
或者useContext
就可以接收到这个数据,无论组件之间跨越了多少层级都可以传递数据最常见使用到的场景就是网站的一件换肤
// 创建context对象与生产者消费者对象
import React from 'react'
export const ThemeContext = React.createContext({themeColor:'skyblue'})
export const ThemeProvider = ThemeContext.Provider
export const ThemeConsumer = ThemeContext.Consumer
// 生产者使用
const Index = ()=>{
return (
return (
<div>
<button onClick={changeColor}>一键换肤</button>
<ThemeProvider value={theme}>
<UseContextPage />
<ContextTypePage />
</ThemeProvider>
</div>
)
}
// 使用contextType接收context对象
class Index extends Component {
// 类组件固定写法 这个 静态属性 名字不能改 赋值的就是提供Provider的那个对象
static contextType = ThemeContext
render() {
const { themeColor } = this.context
return (
<div className={themeColor}>换肤功能已经上线</div>
)
}
}
// 使用useContext接收context对象
const Index = () => {
// 使用hooks接收 赋值的就是提供Provider的那个对象
const { themeColor } = useContext(ThemeContext)
return (
<div className={themeColor}>换肤功能已经上线</div>
)
}
// 使用Consumer接收context对象
class Index extends Component {
render() {
return (
<div>
<ThemeConsumer>
{(themeContext) => (<div className={themeContext.themeColor}>换肤功能已经上线</div>)}
</ThemeConsumer>
</div>
)
}
}
contextType与useContext与consumer的区别
-
contextType方式只能用在类组件中
-
useContext只能用在函数组件和自定义hooks中
-
contextType只能订阅单一的context来源,useContext可以读取多个
// contextType class Index extends Component { static contextType = ThemeContext static contextType = UserContext//后写的会覆盖先写的 } // useContext const Index = () => { // 两个都会生效 const { themeColor } = useContext(ThemeContext) const { user } = useContext(UserContext) }
-
在类组件中如果想接收多个context源,则可以使用 consumer 来接收
真实项目中不会这么用,但是可以实现的
class Index extends Component { render() { return ( <div> <ThemeConsumer> {(themeContext) => (<div className={themeContext.themeColor}>换肤功能已经上线</div>)} <UserConsumer> {userContext => <p>user:{userContext.user}</p> </UserConsumer> </ThemeConsumer> </div> ) } }
-
consumer没有那么多限制了,可以用在类组件也可以使用也可以在函数组件中使用