如图:APP
界面嵌套A
嵌套B
嵌套C
嵌套D
嵌套E
嵌套F
......
场景一:从APP
界面获取数据,需要F
来显示,怎么把APP
界面的值传递给F
?使用props
一层一层的逐级向下传递么😢
场景二:最底层F
需要触发一个事件onClick
,需要APP界面来接受参数并进行下一步的操作,怎么在F
中触发onClick
然后APP
界面也响应进行处理?使用props{callBack=>{}}
逐级向上传递么😢
answer:NO
API
赶快使用 Context 吧~
let { Provider, Consumer } = React.createContext()
创建一对{ Provider, Consumer }
。当 React 渲染 context 组件 Consumer
时,它将从组件树的上层中最接近的匹配的 Provider
读取当前的 context
值。
React.createContext(defaultValue)
可以指定默认值,当Provider
没有value
时,Consumer
中取的就是defaultValue
;当Provide
r存在value
时,会把defaultValue
进行覆盖,Consume
r中取的就是Provider
的value
-
Provider
和Consumer
是 一一对应滴~BConsumer
是取不到AProvider
中的value
滴~-
Provider
组件的value
值发生变更时,其内部组件树中对应的Consumer
组件会接收到新值并重新执行 内部 函数。此过程不受shouldComponentUpdete
方法的影响。-
Provider
组件利用Object.is
检测value
的值是否有更新。注意Object.is
和===
的行为不完全相同呀
Provider
<Provider value={/* some value */}>
...
</Provider>
接收一个 value
属性传递给Provider
的后代 Consumers
。一个 Provider
可以链接到多个 Consumers
。Providers
可以被嵌套以覆盖组件树内更深层次的值。
Provider
包裹的组价内部 可以通过Consumers
访问到 Provider
的value
值
⚠️⚠️⚠️注意:尽量不要在这里
<Provider value={/* some value */}>
给value
赋具体的值,比如<Provider value={{key: 'value',key1: 'value1'...}}
因为只要render
执行一次,Provider
的value
就会返回一个全新的{}
,不管里面的值是否改变,与Provider
对应的Consumer
都会重新执行一次。为了减少不必要的刷新,尽量使用state
,然后配合PureComponent
进行性能优化
Consumer
<Consumer>
{
value => {
coding......
}
}
</Consumer>
注意 Consumer
内部是一个方法,有一个value
。这个参数就是 Provider
的 value
。得到value
,可以在方法里面进行相应的操作,返回组件或者存值都可以
image.png
image.png
使用
context.js
import React from "react";
const AppContext = React.createContext()
const AContext = React.createContext()
const BContext = React.createContext()
export {
AppContext,
AContext,
BContext
}
APP界面
this.state = {
title: '123',
}
render() {
return (
<View>
<TouchableOpacity style={{marginTop: 50, width: 100 ,height: 44, backgroundColor: 'white',justifyContent: 'center',alignItems: 'center'}}
onPress={()=>{
// 点击按钮修改数据
this.setState({
title: '456'
})
}}>
<Text>点击改变数据</Text>
</TouchableOpacity>
//Provider 包裹组件
<AppContext.Provider value={this.state}>
<A/>
</AppContext.Provider>
</View>
);
}
A中有B中有C中有D中有E中有F,代码就不都贴了 只贴F中的代码
F
render() {
return (
<View style={styles.view}>
<Text style={styles.text}>F</Text>
<TouchableOpacity onPress={()=>{
}}>
<Text style={styles.text}>点击在根视图触发方法</Text>
</TouchableOpacity>
<AppContext.Consumer>
{
context => {
// 可以获取到 context 在其他地方进行处理
this.contextDataApp = context
return <View>
<Text style={styles.text}>context App:{context.title}</Text>
</View>
}
}
</AppContext.Consumer>
</View>
);
}
OK 以上代码就可以解决场景一
的问题了,不需要每一层都需要props进行向下传递数据。
开始解决场景二
的问题,其实方法和props
差不多,传递到Consumer
中的value
中含有一个方法即可
APP
this.state = {
title: '123',
bottomClick:this.bottomClick
}
bottomClick(){
console.log('顶层视图 方法调用 bottomClick')
}
<AppContext.Provider value={this.state}>
...
</AppContext.Provider>
F
render() {
return (
<View style={styles.view}>
<Text style={styles.text}>F</Text>
<TouchableOpacity onPress={()=>{
// 在此处也可以调用
this.contextDataApp.bottomClick()
}}>
<Text style={styles.text}>点击在根视图触发方法</Text>
</TouchableOpacity>
<AppContext.Consumer>
{
context => {
// 可以获取到 context 在其他地方进行处理
this.contextDataApp = context
return <View>
<Text onPress={()=>{
context.bottomClick() //也可以传递参数
}} style={styles.text}>context App:{context.title}</Text>
</View>
}
}
</AppContext.Consumer>
</View>
);
}
ok 以上代码就可以解决场景二
的问题了
延伸一点点~
由于 AppContext.Provider
可以对应很多个 AppContext.Consumer
如果 AppContext.Provider
的 value
确定,有很多个组件需要 value
的值,那岂不是每个组价都要使用 AppContext.Consumer
进行包裹~
蹬蹬蹬蹬蹬蹬蹬蹬丢丢丢
高阶组件登场 ~
高阶组件的介绍和使用点这里喽~
高阶组件
import React, {Component} from 'react'
import {AppContext} from './TestContext'
import App from "../App";
export default (WrappedComponent) => {
class NewComponent extends Component {
render(){
return <AppContext.Consumer>
{
context=><WrappedComponent {...this.props} context={context}/>
}
</AppContext.Consumer>
}
}
return NewComponent
}
这里<WrappedComponent {...this.props} context={context}/>
传递给普通组件一个 props
,普通组件可以使用this.props.context
进行数据操作
使用 E 页面 进行模拟
import React, {PureComponent, Component} from 'react';
import {BackAndroid,
TouchableOpacity,
View,
StyleSheet,
Dimensions,
Text
} from "react-native"
const {width, height} = Dimensions.get('window')
import PropTypes from 'prop-types'
import F from './F'
import HocCompenent from './hocComponent'
class E extends Component {
componentDidMount() {
// 拿到 顶层视图的 value
console.log('E this.props.context=',this.props.context)
}
render() {
return (
<View style={styles.view}>
<Text style={styles.text}>E context:{this.props.context.title}</Text>
<F/>
</View>
);
}
}
const styles = StyleSheet.create({
view: {
width: width - 60 - 60 - 60 - 60,
height: height - 44 - 60 - 60 - 60 - 60,
backgroundColor: 'red',
justifyContent: 'center',
alignItems: 'center'
},
text: {
color: 'white',
fontSize: 20
}
})
// 高阶组件使用
export default HocCompenent(E)
最后的最后~
神坑在此~,诸位神魔自行入坑~
Provider不是你想用就可以用的~
最开始使用的旧版本的 API(react16.3.0以前)
,旧版本限制太多,还是别使用,具体的可自行百度、google。
使用新版本的API,还要看 react 和 reactNative 版本~~😭
新建最新的项目 使用Provider 会报 undefined is not an object (evaluating 'context._currentValue = currentValue')
或者 Cannot set property '_currentValue' of undefined
等~错误
要不说google大法好呢,google work ~~ 不过还是要多关注Issues~
不得不说得吐槽下 开发人员了。。。。这么多人提问题,,,你们新建一个项目用一下不就知道了么,咋不自测下呢~
网友评论