開發過程中遇到的問題

  1. try catch 在接口中使用注意

使用 try catch 的使用無論是在 try 中的代碼還是在 catch 中的代碼性能消耗都是一樣的。需要注意的性能消耗在于 try catch 中不要直接塞進去太多的代碼(聲明太多的變量),最好是吧所有要執行的代碼放在另一個 function 中,通過調用這個 function 來執行。針對第二點,可以查看 ECMA 中關于 try catch 的解釋,在代碼進入 try catch 的時候 js引擎會拷貝當前的詞法環境,拷貝的其實就是當前 scope 下的所有的變量。建議在使用 try catch 的時候盡量把 try catch 放在一個相對干凈的 scope 中,同時在 try catch 語句中也盡量保證足夠少的變量,最好通過函數調用方式來 try catch。

   try {
        yield call(services.deleteComment, i, commentid);
        Toast.success('刪除成功',1.5);
        yield put(routerRedux.push('/notebooks/comment'));
      } catch (e) {
        Toast.fail('刪除失敗',1.5);
      }

2.在開發過程中程序會在不同手機的瀏覽器進行使用,偶爾會在操作中出現以下現象:

image.png

點著點著會引發瀏覽器自帶選中文字狀態。
解決方案(不可復制,不可選擇)

 body {
    -webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
  }
  1. 在react+antd+dva的項目中集成html2canvas截圖功能

首先在已經創建好得項目的文件夾下找到 index.ejs 這個文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>111</title>
</head>
<body>
  <div id="root" style="background: #efefef"></div>
</body>
<script src="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.js"></script>
</html>

導入在線的/html2canvas.js文件,然后在寫一個頁面,正文如下:

screenshot(event){// 截圖并保存到本地
         html2canvas(document.body).then(function(canvas) {    
            canvas.id = "mycanvas";         
            let newImg = document.createElement("img");  
            let newSrc = document.createElement("a");  
            let type = 'png';
            let imgData = canvas.toDataURL(type);
            let saveFile = function(data, filename){
            let save_link = document.createElementNS('http://www.x3.org/1999/xtml', 'a');
                save_link.href = data;
                save_link.download = filename;
                let event = document.createEvent('MouseEvents');
                event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                save_link.dispatchEvent(event);
            };
            let filename = '圖片名' + (new Date()).getTime() + '.' + 'png';
            let ua = navigator.userAgent.toLowerCase();   
                  saveFile(imgData,filename);
                  newImg.src =  imgData;   
          })    
    }

return(
<div>
        <div id="textArea"> 11111111111</div>
        <button onclick={(event) => this.screenshot(event)}>截圖</button>
</div>
)

4.實時通訊(該demo只是前端的部分)

css:

         .labText {
             min-height: 230px;
             border: solid 1px #eee;
             width: 1000px;
             margin: 10px auto;
             height: 300px;
             overflow-y: scroll;
         }

html:

<input type="text" id="txtSendText" /><input id="btnSend" type="button" value="send" />
<div id="labText">消息:</div> 
<script src="jquery-1.8.3.min.js"></script>
<script src="jquery.signalR-2.1.2.min.js"></script>
<script src="http://192.168.118.100:8080/signalr/hubs"></script>
 // 此文件是在c#中下載signalR自動生成的,最好后端放在服務器上,你直接寫路徑。

js:

     function showMessage(msg) {
            $("#labText").append("<div>" + msg + "</div>");
        }
     $(function () {
        // Declare a proxy to reference the hub.
        var hub = $.connection.Hub;
        console.log(hub)
        $.connection.hub.qs = {patientName:"jack",id:9000};
        $.connection.hub.url = "http://192.168.118.100:8080/signalr"; // 是服務器上的文件

        // Create a function that the hub can call to broadcast messages.
        hub.client.sendMessage = function (msg) {
            $("#labText").append("<div>" + msg+"</div>");

        };
        hub.client.BroadcastMessage = (msg) => {
            showMessage(msg);
        };
        // Start the connection.
        $.connection.hub.start({jsonp:true}).done(() => {
            alert("啟動成功!");
            $("#btnSend").click(function() {
                var msg = $("#txtSendText").val();
                console.log(msg)
                hub.server.sendToAll(msg);
                $("#txtSendText").val("").focus();
            });
            // hub.server.hello();
        });
        $.connection.hub.error((error) => {
            // showMessage("啟動成功!");
            console.log(error)
            alert("啟動失?。?)
        });

    });

5.this.setState的寫法表示不同的含義
驅動組件渲染的過程中除了prop, 還有state,state代表的是組件內部的狀態。由于React組件不能修改傳入的prop,所以需要記錄自身數據變化,就要使用state。

示例:

 this.setState({...owner, name: ‘Jason'}) 
//   相當于把name鍵值對添加到owner對象里(把owner對象里面的name的值替換成Jason)     
 this.setState(...owner, {name: ‘Jason’}) 
//   把整個owner對象替換為 name: Jason

舉例:

     let aWithOverrides = { …a, x: 1, y: 2 };
    //  等同于
     let aWithOverrides =  { …a, …{ x: 1; y: 2} };
    //  等同于
     let x = 1, y = 2, aWithOverrides = { ...a, x, y };
    //  等同于
     let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 });
  1. react中組件被重新渲染(閃屏現象)

簡介:ShouldCompleteUpdate,下文簡稱SCU,就是指明什么時候component(組件)需要進行更新。

示例:

 constructor(props) {
        super(props);
        this.onClickButton = this.onClickButton.bind(this);
        this.state = { count: 0};
  }
 shouldComponentUpdate(nextProps, nextState) {
      if (this.state.count !== nextState.count) {
        return true;
      }
      return false;
  }
onClickButton() {
        this.setState({ count: this.state.count + 1 });
  }
// 其中的state.count的值要被改變的,我們可以直接用SCU
// 組件僅僅會校驗state.count,如果這些值都不會改變,那么組件就不會有更新。

舉例:

  constructor(props) {
      super(props);
       // console.log(this.props);
      this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
      this.onClickDecrementButton = this.onClickDecrementButton.bind(this);
      // this.foo = ::this.foo 其他教程中可以這樣去編寫它
      // this.foo = this.foo.bind(this)

      this.state = {
        count: props.initValue // initValue 是一個可選的props 
      }
    }

  /*
  getInitialState() {
    getInitialState的返回值用來初始化組件的this.state,只有用React.createClass方法創造的組件類才會起作用,
    在這里這個函數是根本不起作用的
    console.log('enter getInitialState');
  }

  getDefaultProps() {

    console.log('enter getDefaultProps');
  }
  */
  componentWillReceiveProps(nextProps) {}

  componentWillMount() {}

  componentDidMount() {}

  onClickIncrementButton() {
    this.setState({count: this.state.count + 1}); 
  }

  onClickDecrementButton() {
    this.setState({count: this.state.count - 1});
  }

  shouldComponentUpdate(nextProps, nextState) {
    return (nextProps.caption !== this.props.caption) ||
           (nextState.count !== this.state.count);
  }
// 
當頁面重新被渲染之前,把一些不必要的和沒有渲染的節點進行處理。
因為頁面的兩部分分別渲染5000個節點,從1-5000。
當點擊按鈕之后,第二部分的節點會更新,重新渲染從2-5001的數字,但是第一部分保持不變。
所以說SCU是在組件沒被二次渲染之前刪掉一些浪費的渲染。
shouldComponentUpdate這個函數是必須是在react的生命周期函數中去調用。
//

7.在react中導入iconfont圖標字體遇到的狀況

首先:
(1)去阿里矢量圖官網http://www.iconfont.cn/添加你所喜歡的iconfont,然后你的購物車里面就是你添加的iconfont。

one.png

(2)把購物車中iconfont添加已有的項目qqq中去,如果沒有的可以在右上腳新建新的項目

two.png

(3)把項目的代碼復制下來,跟本地添加iconfont一樣。
three.jpg

示例如下:
(3)index.css中內容

// 本地和導入項目 這個是固定的
.iconfont{
    font-family:"iconfont";
    font-size:40px;
    font-style:normal;
}

//這個就是你復制在iconfont上的代碼鏈接(你添加在項目中的iconfont)
@font-face {
  font-family: 'iconfont';  /* project id 499958 */
  src: url('//at.alicdn.com/t/font_499958_759xzvyfw16k1emi.eot');
  src: url('//at.alicdn.com/t/font_499958_759xzvyfw16k1emi.eot?#iefix') format('embedded-opentype'),
  url('//at.alicdn.com/t/font_499958_759xzvyfw16k1emi.woff') format('woff'),
  url('//at.alicdn.com/t/font_499958_759xzvyfw16k1emi.ttf') format('truetype'),
  url('//at.alicdn.com/t/font_499958_759xzvyfw16k1emi.svg#iconfont') format('svg');
}

(4)在頁面上的使用:

import styles from './index.css';// 引入CSS

render() {
    return (
      <div>
              <i className="iconfont">&#xe617;</i>// 老版本的寫法
              <i className={styles.iconfont}>&#xe617;</i>// 目前的寫法
      </div>
     )
 }

8.react(dva)+antd創建項目之后的路由問題

(1)之前低版本的路由是可以有嵌套關系的

示例如下:

  return (
      <Router history={history}>
          <Route path="/" component={Layout}>
              <IndexRoute component={HealthyPage} />
              <Route path="department" component={DepartPage} />
              <Route path="signin" component={SigninPage} />
              <Route path="signup">
                    <IndexRoute component={SignupMobilePage} />
                    <Route path="2" component={SignupPasswordPage} />
                    <Route path="3" component={SignupUserInfoPage} />
              </Route>
              <Route path="forgot">
                    <IndexRoute component={ForgotPasswordPage} />
                    <Route path="reset" component={ResetPasswordPage} />
              </Route>
              <Route path="signauth" component={SignAuthPage} />
              <Route path="doctor" onEnter={() => requireAuth(app._store)}>
                    <IndexRoute component={DoctorPage} />
                    <Route path=":id" component={ConversationPage} />
              </Route>
              <Route path="healthy" onEnter={() => requireAuth(app._store)}>
              </Route>
      </Router>
  )

使用IndexRoute有利于代碼分離,也有利于使用React Router提供的各種API。IndexRoute組件沒有路徑參數path。

(2) 當前版本的路由是不可以嵌套的

示例如下:

 <Router history={history}>
      <Switch>
          <Route path="/" exact component={SinAuthPage} />
          <Route path="/IndexPage" exact component={IndexPage} />
          <Route path="/Clickmobile" exact component={Clickmobile} />
          <Route path="/IndexPage/chd" exact component={chd} />
          <Route path="/IndexPage/pre" exact component={pre} />
          <Route path="/IndexPage/dia" exact component={dia} />
          <Route path="/IndexPage/phy" exact component={phy} />
          <Route path="/IndexPage/partum" exact component={partum} />
      </Switch>
    </Router>

現在是變的是單個頁面要單個單個的去寫,不能像之前的嵌套關系比較復雜啦。如果像之前那樣去寫的話會報以下的錯誤:
Syntax error: Expected corresponding JSX closing tag for <Switch>

什么意思呢?意思就是說:相關的jsx語法有問題 直接報的是代碼有問題。

目前還有找到相對應的解決方案。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯系作者。

推薦閱讀更多精彩內容