text: ## Getting started with React
  [![license](http://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat)](https://github.com/Tencent/VasSonic/blob/master/LICENSE)
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/VasSonic/pulls)
  [![wiki](https://img.shields.io/badge/Wiki-open-brightgreen.svg)](https://github.com/Tencent/VasSonic/wiki)
  ---
  
  ## How to use the demo
  
  >This demo will give you a quick start for using Sonic with React.
  
  ### Dependencies
  Node Version > 7.0
  ### Installation
  ```bash
  git clone https://github.com/Tencent/VasSonic.git <my-project-name>
  cd <my-project-name>/sonic-react
  npm install  # Install project dependencies
  ```
  ### Usage
  ```bash
  npm run build  # Builds the application to ./.next
  npm start      # Start the development server
  ```
  Now you can visit http://localhost:3000/demo to view this demo using Mobile Emulation Mode in Chrome dev tools.
  
  ## How to use Sonic on server-side
  
  >NOTE: This demo using Server Side Rendering (SSR) with [Redux](https://redux.js.org/), [Next.js](https://github.com/zeit/next.js/) and [Koa2](http://koajs.com/).
  
  1. Add comment tags to separate **template** and **data blocks** in html files which will be published from the server. The **data blocks** should begin with a html comment like `<!-- sonicdiff-moduleName -->` and close with `<!-- sonicdiff-moduleName-end -->`(the moduleName is custom). And the other part of the html is called **template** in Sonic. In this demo, it is implemented like the code shown below.
  
  - Below is the origin html, we will generate comment tags according to the `data-sonicdiff` attribute and the script block including `__NEXT_DATA__`:
  
  ```HTML
  <!-- add comment tags to separate template and data blocks from the initial html -->
  <!DOCTYPE html>
  <html>
    <head></head>
    <body>
      … …
      <div id="root" data-sonicdiff="firstScreenHtml">
      … …
      </div>
      … …
      <script>
        __NEXT_DATA__=xxx
      </script>
    </body>
  </html>
  ```
  
  - Then, we have a transform function at server side:
  
  ```js
  function formatHtml(html) {
      const $ = cheerio.load(html);
      $('*[data-sonicdiff]').each(function(index, element) {
          let tagName = $(this).data('sonicdiff');
          return $(this).replaceWith('<!--sonicdiff-' + tagName + '-->' + $(this).clone() + '<!--sonicdiff-' + tagName + '-end-->');
      });
      html = $.html();
      html = html.replace(/<script\s*>\s*__NEXT_DATA__\s*=([\s\S]+?)<\/script>/ig, function(data1) {
          return '<!--sonicdiff-initState-->' + data1 + '<!--sonicdiff-initState-end-->';
      });
      return html;
  }
  ```
  - After the transform, the latest code user will received will be like:
  
  ```HTML
  <!-- add comment tags to separate template and data blocks from the initial html -->
  <!DOCTYPE html>
  <html>
    <head></head>
    <body>
      … …
  +   <!-- sonicdiff-firstScreenHtml -->
      <div id="root" data-sonicdiff="firstScreenHtml">
      … …
      </div>
  +   <!-- sonicdiff-firstScreenHtml-end -->
      … …
  +   <!-- sonicdiff-initState -->
      <script>
        __NEXT_DATA__=xxx
      </script>
  +   <!-- sonicdiff-initState-end -->
    </body>
  </html>
  ```
  
  2. Intercept the html response from server and use [sonic_differ](https://github.com/Tencent/VasSonic/blob/master/sonic-nodejs/common/diff.js) module to process the response.
  
  ```js
  server.use(async (ctx, next) => {
      await next();
      // only intercept html request
      if (!ctx.response.is('html')) {
          return;
      }
      // process non-sonic mode
      if (!ctx.request.header['accept-diff']) {
          ctx.body = ctx.state.resHtml;
          return;
      }
      // use sonic_differ module to process the response
      let sonicData = sonicDiff(ctx, formatHtml(ctx.state.resHtml));
      if (sonicData.cache) {
          // 304 Not Modified, return nothing.
          ctx.body = '';
      } else {
          // other Sonic status.
          ctx.body = sonicData.data;
      }
  });
  ```
  
    For more details please refer to [server.js](https://github.com/Tencent/VasSonic/blob/master/sonic-react/server.js).
  
  ## How to use Sonic on client-side
  
  Handle the response from mobile client which include Sonic response code and diff data in `componentDidMount()`.
  
  ```js
  componentDidMount() {
      // handle the response from mobile client which include Sonic response code and diff data.
      this.getSonicData((status, sonicUpdateData) => {
          switch (status) {
              // here, we only process the case when data updates
              case 3:
                  // update the Redux store based on changes from the mobile client
                  let initState = sonicUpdateData['{initState}'] || '';
                  initState.replace(/<!--sonicdiff-initState-->\s*<script>\s*__NEXT_DATA__\s*=([\s\S]+?)module=/ig, function(matched, $1) {
                      window.__NEXT_DATA__ = JSON.parse($1);
                  });
                  this.props.initImgArr(window.__NEXT_DATA__.props.initialState.gameArea);
                  break;
              default:
                  break
          }
          // display sonic status
          this.props.setSonicStatus(status);
      });
  }
  
  getSonicData(callback) {
      let sonicHadExecute = 0;   // whether the callback is triggered
      const timeout = 3000;      // a timeout to trigger callback
  
      // Interacts with mobile client by JavaScript interface to get Sonic diff data.
      window.sonic && window.sonic.getDiffData();
  
      function sonicCallback(data) {
          if (sonicHadExecute === 0) {
              sonicHadExecute = 1;
              callback(data['sonicStatus'], data['sonicUpdateData']);
          }
      }
  
      setTimeout(function() {
          if (sonicHadExecute === 0) {
              sonicHadExecute = 1;
              callback(0, {});
          }
      }, timeout);
  
      // the mobile client will invoke method getDiffDataCallback which can send Sonic response code and diff data to websites.
      window['getDiffDataCallback'] = function (sonicData) {
          /**
           * Sonic status:
           * 0: It fails to get any data from mobile client.
           * 1: It is first time for mobile client to use Sonic.
           * 2: Mobile client reload the whole websites.
           * 3: Websites will be updated dynamically with local refresh.
           * 4: The Sonic request of mobile client receives a 304 response code and nothing has been modified.
           */
          let sonicStatus = 0;
          let sonicUpdateData = {};  // sonic diff data
          sonicData = JSON.parse(sonicData);
          switch (parseInt(sonicData['srcCode'], 10)) {
              case 1000:
                  sonicStatus = 1;
                  break;
              case 2000:
                  sonicStatus = 2;
                  break;
              case 200:
                  sonicStatus = 3;
                  sonicUpdateData = JSON.parse(sonicData['result'] || '{}');
                  break;
              case 304:
                  sonicStatus = 4;
                  break;
          }
          sonicCallback({ sonicStatus: sonicStatus, sonicUpdateData: sonicUpdateData });
      };
  }
  ```
  For more details please refer to [demo.js](https://github.com/Tencent/VasSonic/blob/master/sonic-react/pages/demo.js)
  
  ## Support
  Any problem?
  
  1. Learn more from [sample](https://github.com/Tencent/VasSonic/tree/master/sonic-react).
  2. Contact us for help.
  
  ## License
  VasSonic is under the BSD license. See the [LICENSE](https://github.com/Tencent/VasSonic/blob/master/LICENSE) file for details.
  