踩坑场景

在做业务的时候,有些模块是可以拖动的,恰好这些模块需要从根组件App的context上拿属性,同时App也是作为拖动上下文,被@DragDropContext(HTML5Backend)装饰,当时年少无知,无脑写下了以下代码

const boxSource = {canDrag(props, monitor) {...},beginDrag(props) {...},endDrag(props, monitor) {...},
};
@DragSource('box', boxSource, (connect, monitor) => ({connectDragSource: connect.dragSource(),isDragging: monitor.isDragging(),
}))
export default class Box extends Component {static contextTypes = {value: PropTypes.number
};static propTypes = {...}render() {const { isDragging, connectDragSource, src } = this.props;const { value } = this.context;return (connectDragSource(...));}
}

美滋滋啊,美滋滋啊,so ez,会用react-dnd了,赶紧将代码跑起来,结果傻眼了,居然报这个错误

Invariant Violation: Could not find the drag and drop manager in the context of Box. Make sure to wrap the top-level component of your app with DragDropContext. Read more: http://react-dnd.github.io/react-dnd/docs-troubleshooting.html#could-not-find-the-drag-and-drop-manager-in-the-context

提示我们在拖拽组件Box的context上找不到react-dnd需要的drag and drop manager,懵了,让我想想是咋回事,是不是最后给

  static contextTypes = {value: PropTypes.number}

给覆盖了原来的Box.contextTypes呀?
不过这也简单,不让他覆盖就好了嘛,于是我写下了如下的代码

Box.contextTypes = Object.assign(Box.contextTypes,{value: PropTypes.number
});

真好,报错消失了,大功告成!等等,this.context.value怎么是undefined,拿不到了?我明明在contextTypes里声明了呀,不行,还是得去看一看源码。

React-dnd源码

查看DragSource的源码,可以看到DragSource就是一个普通装饰器包装函数

function DragSource(type, spec, collect, options = {}) {
...
return function decorateSource(DecoratedComponent) {return decorateHandler({connectBackend: (backend, sourceId) => backend.connectDragSource(sourceId),containerDisplayName: 'DragSource',createHandler: createSource,registerHandler: registerSource,createMonitor: createSourceMonitor,createConnector: createSourceConnector,DecoratedComponent,getType,collect,options,});};
}

那我们继续去看一看 decorateHandler这个函数呗

export default function decorateHandler({DecoratedComponent,createHandler,createMonitor,createConnector,registerHandler,containerDisplayName,getType,collect,options,
}) {
...class DragDropContainer extends Component {...static contextTypes = {dragDropManager: PropTypes.object.isRequired,}...render() {return (<DecoratedComponent{...this.props}{...this.state}ref={this.handleChildRef}/>);}}return hoistStatics(DragDropContainer, DecoratedComponent);
}

嗯, decorateHandler就是一个HOC生成函数嘛,hoistStatics就是hoist-non-react-statics这个库,做过HOC的童鞋一定不陌生,他就是将WrappedComponent的静态方法和静态属性提到HOC上,面,避免WrappedComponent的静态属性和静态方法丢失了,看似挺合理,嗯嗯。等等!这不就用WrappedComponent的contextTypes将HOC的contextTypes给覆盖了么?这也很合理的解释了为啥会报错了。

解决步骤

知道了其中的原来,那我们就让HOC和WrappedComponent各自保留一份contextTypes好了,首先我们需要用另一个变量来保留对WrappedComponent的引用,因为被@DragSource装饰后,WrappedComponent的变量名就会被HOC覆盖了,然后我们再对WrappedComponent加上contextTypes就好了,代码如下:

class Box extends Component {static propTypes = {connectDragSource: PropTypes.func.isRequired,...}render() {const { isDragging, connectDragSource, src } = this.props;const { value } = this.context;...return (connectDragSource(...));}
}const Temp = Box;
const Box1 = DragSource('box', boxSource, (connect, monitor) => ({connectDragSource: connect.dragSource(),isDragging: monitor.isDragging(),
}))(Box);
Temp.contextTypes = {value: PropTypes.number,
}
export default Box1;

大功告成,我们再来跑一跑。
哇,又报错了,囧,说

Invariant Violation: App.getChildContext(): childContextTypes must be defined in order to use getChildContext().

好,那我们来看看根组件咋回事,我写的根组件如下

@DragDropContext(HTML5Backend)
class App extends React.Component {constructor(props) {super(props);}static childContextTypes = {value:PropTypes.number,}getChildContext(){return {value:1}}render() {return (<Box />)}
}

让我们看看DragDropContext源码

export default function DragDropContext(backendOrModule) {...return function decorateContext(DecoratedComponent) {...class DragDropContextContainer extends Component {getChildContext() {return childContext;}render() {return (<DecoratedComponent{...this.props}ref={(child) => { this.child = child; }}/>);}}return hoistStatics(DragDropContextContainer, DecoratedComponent);};
}

得,又是HOC的问题,但是有点不同,就是contextTypes一定要准确设置在需要的组件上,但是childContextTypes只要放在上层组件就可以了,所以我做了如下修改:

  • 删去class App 中的
 static childContextType = {value: PropTypes.number}
  • 加上一下代码
App.childContextTypes = Object.assign(App.childContextTypes,{value: PropTypes.number
});

这次总该行了吧,心累啊。嗯?还是拿不到this.context.value,想起来了!,虽然hoist-non-react-statics将静态属性拿了出来,但是原型方法不会拿出来啊,所以WrappedComponent的getChildContext就没用了,所以我们需要也将他拿出来,于是,加上一下代码

const temp = {...App.prototype.getChildContext()};
App.prototype.getChildContext = () => ({...temp, value:1})

这次总算拿到正确的结果了,开心

react-dnd中context丢失解决方法相关推荐

  1. 计算机中丢失vulkan-1.dll,德军总部2新巨像vulkan-1.dll丢失怎么办 vulkan-1.dll丢失解决方法...

    德军总部2新巨像vulkan-1.dll丢失怎么办?不少玩家朋友们在进入游戏后会出现各种问题导致无法进入游戏,下面我们就来看一看德军总部2新巨像vulkan-1.dll丢失解决方法一览,希望对各位有所 ...

  2. 附件 计算机 丢失,Win10系统开始菜单中没有附件解决方法

    在使用电脑的时候经常会遇到各种难题,例如有些伙伴们说自己的电脑Win10开始菜单中附件不见了怎么回事的现象,像遇到这样的问题该如何解决呢?其实非常简单,对于Win10系统开始菜单中没有附件解决方法的问 ...

  3. Java中double类型精度丢失的问题_double类型数据加减操作精度丢失解决方法_BigDecimal取整

    BigDecimal在用double做入参的时候,二进制无法精确地表示十进制小数,编译器读到字符串"0.0000002"和"1.0000002"之后,必须把它转 ...

  4. Windows 2000/NT/XP管理员密码丢失解决方法

    Windows 2000/NT/XP管理员密码丢失解决方法 2003-10-30 CERT.SWJTU.EDU.CN 经常被问即管理员密码丢失怎么办?下边就windows 2000/nt/xp系统下的 ...

  5. win8计算机丢失xinput1+3.dll,xinput1 3.dll丢失怎么办 win8下xinput1 3.dll丢失解决方法

    xinput1 3.dll是Microsoft DirectX for Windows的控制模块,它适合于WinXP,Vista,Win7,Win8系统.当运行程序或者游戏时,系统弹出错误提示&quo ...

  6. 计算机里的文件丢失6,u盘修复后文件丢失解决方法

    相信有很多朋友都遇到过u盘修复后文件丢失的情况,那么修复u盘后文件丢失的话我们要如何解决呢?说实话小编早就在研究修复u盘后文件丢失的问题了!下面win7之家小编就给大家带来u盘修复后文件丢失的解决方法 ...

  7. 无法启动此程序因为计算机丢失zlib.dll,zlib1.dll怎么修复?zlib1.dll丢失解决方法及注意事项...

    zlib1.dll怎么修复? 小编胖胖带来了zlib1.dll丢失解决方法,很多朋友在使用电脑时会提示"没有找到zlib1.dll",该如何解决呢?请试一试下文提供的解决方法吧~ ...

  8. ESP8266-Arduino网络编程实例-WiFi连接丢失解决方法

    WiFi连接丢失解决方法 在实际应用中,WiFi连接上的,有可能存在连接断开的情况.比如, ESP8266 暂时失去 Wi-Fi 信号: ESP8266 暂时不在路由器的 Wi-Fi 范围内: 路由器 ...

  9. 群晖网络不通_群晖系统安装zerotier one进行内网穿透过程中常见问题及解决方法...

    群晖系统安装zerotier one进行内网穿透过程中常见问题及解决方法 2020-07-28 17:27:39 21点赞 330收藏 31评论 zerotier one是一款很好用的P2P内网穿透软 ...

最新文章

  1. 压缩工具gzip,bzip2,xz,zip,tar
  2. R语言绘制Bump Chart
  3. Request和Response-学习笔记05【ServletContext对象、文件下载】
  4. Xampp中的apache,tomcat无法启动的问题
  5. 分布式架构的NoSQL
  6. e2200网卡驱动 linux,Linux驱动修炼之道-驱动中一些常见的宏
  7. 联发科有没有高端处理器_2021年华为将成为联发科最大客户?麒麟或将“灭亡?”...
  8. 配置oracle odbc驱动,oracle odbc driver configuration
  9. 在 CentOS 7 上搭建 Jenkins + Maven + Git 持续集成环境
  10. Python 优雅获取本机 IP 方法【转】
  11. Openstack安装(1)--keystone安装
  12. python网络图可视化_蜘蛛网图实现Python可视化的方法
  13. Lora如何组网?有哪些简单的Lora组网协议?
  14. 常用图片jpg png jpeg gif等格式介绍
  15. 程序化交易高手的交易心得 分享~
  16. 机械原理c语言程序,机械原理课程设计心得体会范文
  17. Java程序员的春天!java第三方线程池
  18. CDN概念和基本原理
  19. VideoProc for Mac(全能影片处理软件)
  20. 【OpenCV人脸识别入门教程之二】人脸检测

热门文章

  1. Numerical Geometry of Image
  2. php 函数:func_get_args()、func_get_arg()与func_num_args()
  3. mysql 原理 ~ DDL之在线DDL
  4. 【前端】:jQuery上
  5. rocketmq单机搭建
  6. 小蚂蚁学习mysql性能优化(5)--SQL以及索引优化--需要添加索引的列
  7. 【栈】日志分析(BSOJ2981)
  8. Thread Dump 和Java应用诊断(转)
  9. 有道词典 纯净版 - imsoft.cnblogs
  10. 二级联动菜单,简单实现