react-dnd中context丢失解决方法
踩坑场景在做业务的时候,有些模块是可以拖动的,恰好这些模块需要从根组件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 = Object.assign(Box.contextTypes,{
value: PropTypes.number
});
真好,报错消失了,大功告成!等等,this.context.value怎么是 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,options,});
};
}
那我们继续去看一看 export default function decorateHandler({
DecoratedComponent,createHandler,createMonitor,createConnector,registerHandler,containerDisplayName,}) {
...
class DragDropContainer extends Component {
...
static contextTypes = {
dragDropManager: PropTypes.object.isRequired,}
...
render() {
return (
<DecoratedComponent
{...this.props}
{...this.state}
ref={this.handleChildRef}
/>
);
}
}
return hoistStatics(DragDropContainer,DecoratedComponent);
}
嗯, 解决步骤知道了其中的原来,那我们就让HOC和WrappedComponent各自保留一份contextTypes好了,首先我们需要用另一个变量来保留对WrappedComponent的引用,因为被 class Box extends Component {
static propTypes = {
connectDragSource: PropTypes.func.isRequired,...
}
render() {
const { isDragging,src } = this.props;
const { value } = this.context;
...
return (
connectDragSource(
...
)
);
}
}
const Temp = Box;
const Box1 = DragSource('box',}))(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 />
)
}
}
让我们看看 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只要放在上层组件就可以了,所以我做了如下修改:
static childContextType = {
value: PropTypes.number
}
App.childContextTypes = Object.assign(App.childContextTypes,{
value: PropTypes.number
});
这次总该行了吧,心累啊。嗯?还是拿不到 const temp = {...App.prototype.getChildContext()};
App.prototype.getChildContext = () => ({...temp,value:1})
这次总算拿到正确的结果了,开心 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
