記錄一次react相關總結
背景說明:元旦接到一個管理後臺的專案,是一個關於自定義專題的專案。通過後臺的配置自定義專題,前端根據專題模組進行渲染資料。由於管理後臺是react做的前後分離,對於一個後端的我來說寫寫js也算是淺嘗一下。如下記錄一下工作中遇到的一些問題,和解決方案。
一、父元件呼叫子元件、以及子元件呼叫父元件
為什麼會遇到這個問題,因為目前的需求是是無限增加Tabs標籤,每一個Tabs標籤頁面又可以增加無限個子Tab標籤,由於react只會子頁面第一次載入的時候呼叫一次鉤子函式,後期切換標籤遍不在重新整理頁面,於是就會遇到父親改變,需要改變子元件的資料,子元件改變也需要同步父元件的資料。
(1)父元件呼叫子元件解決方案如下:
let topicComList = [{ title: '輪播排序', content: <GroupSort topicId={that.state.topicId} componentId={this.state.componentId} onRef={this.onRef}/> , key: '1', closable: false }];
1)上面這段程式碼是父元件頁面中書寫的Tab的子元件內容,在子元件傳遞 onRef = { this.onRef }
//實現一個子元件物件 onRef = (ref) => { this.child = ref; }
2)在父元件中實現這個箭頭函式,並且在頁面上定義一個child state
這個的作用是將子元件的物件傳遞給父元件的child,後期便通過this.child.fun()去呼叫子元件的方法
3)子元件這樣寫
componentDidMount() { this.props.onRef(this) this.state.topicId = this.props.topicId; this.topicComponentGroupList(); }
只看第二行,接收父元件傳遞的 onRef 指定一個this即可
4)實現如上操作就可以進行呼叫子元件的方法了,實現如下
if ( typeof this.child == 'object' ) { this.child.onRefFun(); }
這樣就可以正常訪問子元件的onRefFun方法了,其實很方便。
(2)子元件呼叫父元件解決方案如下:
let topicComList = [{ title: '輪播排序', content: <GroupSort topicId={that.state.topicId} componentId={this.state.componentId} clickCallBack={that.clickCallBack} /> , key: '1', closable: false }];
同樣是這樣的一個子元件,給子元件傳遞一個函式 clickCallBack, 子元件便可通過 this.props.clickCallBack()去呼叫父親的函式。
1)首先在父元件實現這個函式 clickCallBack
//子元件呼叫父元件函式 clickCallBack = () => { this.topicComponentGroupList(); }
2)在子元件中,在需要更新父元件的地方,this.props.clickCallBack即可
handleSubmit = (e) => { e.preventDefault(); let that = this; that.setState({ loadingForm: true }); this.props.form.validateFieldsAndScroll((err, values) => { if (!err) { let saveVal = {}; saveVal = { anchors:[{ name: values.groupName, id: values.anchor }] }; that.props.dispatch({ type: 'editgroup/edit', payload: { topicId: that.state.topicId, componentId : this.state.componentId, componentGroupId: that.state.groupId, value: JSON.stringify(saveVal), groupName: values.groupName } }).then(function (response) { Modal.success({ title: '訊息', content: '操作成功!' , }); that.setState({ loadingForm: false, messageType:'success', message:'溫馨提示:恭喜小主,您已儲存成功!' }); that.props.clickCallBack(); }.bind(that)).catch( function ( errmsg ) { Modal.error({ title: '訊息', content: '錯誤資訊: ' + errmsg, }); that.setState({ loadingForm: false }); }); } else { that.setState({ loadingForm: false }); } }); }
以上就是關於元件直接的互相呼叫。
二、如果實現js的非同步執行 Promise
根據需求上傳圖片需要獲取圖片的寬和高,但是由於js都是非同步執行的,往往我這邊的寬和高還沒有或取到,js的操作流程就已經結束了,導致不能夠100%獲取到圖片的寬和高,通過查詢知道 Promise 是專門執行非同步操作的 ,它會等待非同步完成執行完成在繼續執行下去。
寫法如下:
beforeUpload = file => { const { fileSizeLimit = 5 } = this.props; const isJPG = imageTypes.includes(file.type); if (!isJPG) { Modal.error({ title: '只支援上傳圖片型別!' });return false; } const isLt2M = file.size / 1024 / 1024 < fileSizeLimit; if (!isLt2M) { Modal.error({ title: `檔案大小不能超過${fileSizeLimit}M!` });return false; } return isJPG && isLt2M && this.checkImageWH(file); }; checkImageWH = (file) => { let self = this; return new Promise(function (resolve, reject) { let filereader = new FileReader(); filereader.onload = e => { let src = e.target.result; const image = new Image(); image.onload = function () { self.state.imageWidth = this.width; self.state.imageHeight = this.height; if (!self.state.imageWidth) { Modal.error({ title: '請上傳圖片的寬' }) reject(); } else if (!self.state.imageHeight) { Modal.error({ title: '請上傳圖片的高', }) reject(); } else { resolve(); } }; image.onerror = reject; image.src = src; }; filereader.readAsDataURL(file); }); }
以上的關鍵點就在於這一句: return isJPG && isLt2M && this.checkImageWH(file); 同步執行成功才成功,否則就失敗。
由此可見 Promise 最後只會返回成功,或者失敗。
具體可借鑑https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014345008539155e93fc16046d4bb7854943814c4f9dc2000
三、編輯時圖片資訊不顯示出來
原因說明,由於react 渲染頁面render會多次,而圖片元件只會識別第一次的render渲染,從而導致當datasource有資料時圖片資訊不顯示,而其他資料顯示沒有問題。
解決方案:這個方法主要是佔一個坑,不讓頁面走下去,直到有資料時才真正的渲染html
if (this.state.topicId && this.state.dataSource.length === 0) { return <Spin size="large" />; }
以上這些是在這次工作中的解決方案,方便記憶。