摘要:等等這不就用的將的給覆蓋了么這也很合理的解釋了為啥會報錯了。嗯還是拿不到,想起來了,雖然將靜態(tài)屬性拿了出來,但是原型方法不會拿出來啊,所以的就沒用了,所以我們需要也將他拿出來,于是,加上一下代碼這次總算拿到正確的結(jié)果了,開心
踩坑場景
在做業(yè)務(wù)的時候,有些模塊是可以拖動的,恰好這些模塊需要從根組件App的context上拿屬性,同時App也是作為拖動上下文,被@DragDropContext(HTML5Backend)裝飾,當(dāng)時年少無知,無腦寫下了以下代碼
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了,趕緊將代碼跑起來,結(jié)果傻眼了,居然報這個錯誤
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就是一個普通裝飾器包裝函數(shù)
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, }); }; }
那我們繼續(xù)去看一看 decorateHandler這個函數(shù)唄
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 (); } } return hoistStatics(DragDropContainer, DecoratedComponent); }
嗯, decorateHandler就是一個HOC生成函數(shù)嘛,hoistStatics就是hoist-non-react-statics這個庫,做過HOC的童鞋一定不陌生,他就是將WrappedComponent的靜態(tài)方法和靜態(tài)屬性提到HOC上,面,避免WrappedComponent的靜態(tài)屬性和靜態(tài)方法丟失了,看似挺合理,嗯嗯。等等!這不就用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 () } }
讓我們看看DragDropContext源碼
export default function DragDropContext(backendOrModule) { ... return function decorateContext(DecoratedComponent) { ... class DragDropContextContainer extends Component { getChildContext() { return childContext; } render() { return ({ this.child = child; }} /> ); } } return hoistStatics(DragDropContextContainer, DecoratedComponent); }; }
得,又是HOC的問題,但是有點不同,就是contextTypes一定要準(zhǔn)確設(shè)置在需要的組件上,但是childContextTypes只要放在上層組件就可以了,所以我做了如下修改:
刪去class App 中的
static childContextType = { value: PropTypes.number }
加上一下代碼
App.childContextTypes = Object.assign(App.childContextTypes,{ value: PropTypes.number });
這次總該行了吧,心累啊。嗯?還是拿不到this.context.value,想起來了!,雖然hoist-non-react-statics將靜態(tài)屬性拿了出來,但是原型方法不會拿出來啊,所以WrappedComponent的getChildContext就沒用了,所以我們需要也將他拿出來,于是,加上一下代碼
const temp = {...App.prototype.getChildContext()}; App.prototype.getChildContext = () => ({...temp, value:1})
這次總算拿到正確的結(jié)果了,開心
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/87362.html
摘要:不多說,直接上代碼需要版本貌似與方法有關(guān)類似的高階組件包裹被拖的元素高階組件包裹被釋放的元素這個庫是必須的,類似于的合成事件解決瀏覽器差異,抽象事件操作為可以處理的 不多說,直接上代碼 react-dnd 需要react版本 > 16.6 ,貌似與react.memo方法有關(guān) import React from react // DragDropContext 類似React的Co...
摘要:簡介在公司初學(xué)其中一個要求讓我實現(xiàn)拖拽排序的功能完成之后記錄一下實現(xiàn)方法,采用和來實現(xiàn)這個功能。一環(huán)境搭建首先,使用腳手架創(chuàng)建一個最基本的項目。 簡介 在公司初學(xué)react,其中一個要求讓我實現(xiàn)拖拽排序的功能,完成之后記錄一下實現(xiàn)方法,采用antd和reactDND來實現(xiàn)這個功能。 一、環(huán)境搭建 首先,使用 create-react-app 腳手架創(chuàng)建一個最基本的react項目。 np...
摘要:丟失問題文本是為了說清目前的機制是而不是我們以為的機制,并說明這兩者的區(qū)別。雖然明白了原理,但是問題并沒有解決。上下文注意這里是,需要執(zhí)行接受回調(diào)函數(shù),回調(diào)函數(shù)中的內(nèi)容為實測可以成功拿到。 React context 丟失問題 文本是為了說清react context目前的機制是owner context 而不是我們以為的parent context 機制,并說明這兩者的區(qū)別。...
摘要:假如以的作用域鏈作為類比,組件提供的對象其實就好比一個提供給子組件訪問的作用域,而對象的屬性可以看成作用域上的活動對象。所以,我借鑒了作用域鏈的思路,把當(dāng)成是組件的作用域來使用。 前言 Context被翻譯為上下文,在編程領(lǐng)域,這是一個經(jīng)常會接觸到的概念,React中也有。 在React的官方文檔中,Context被歸類為高級部分(Advanced),屬于React的高級API,但官方...
摘要:作用域沒有塊級作用域盡量不要在塊中聲明變量。只有函數(shù)級作用域作用域鏈自由變量當(dāng)前作用域沒有定義的變量即為自由變量。自由變量會去其父級作用域找。 1. 題目 說一下對變量提升的理解 說明this的幾種不同使用場景 創(chuàng)建10個a標(biāo)簽,點擊的時候彈出來相應(yīng)的序號 如何理解作用域 實際開發(fā)中閉包的應(yīng)用 手動實現(xiàn)call apply bind 2. 知識點 2.1 執(zhí)行上下文 范圍:一段scri...
閱讀 2477·2021-11-22 15:35
閱讀 3767·2021-11-04 16:14
閱讀 2696·2021-10-20 13:47
閱讀 2507·2021-10-13 09:49
閱讀 2077·2019-08-30 14:09
閱讀 2376·2019-08-26 13:49
閱讀 887·2019-08-26 10:45
閱讀 2778·2019-08-23 17:54