1. 程式人生 > >記錄一次react相關總結

記錄一次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" />;
 }

以上這些是在這次工作中的解決方案,方便記憶。