Skip to content
久久日记本
曾经年少爱追梦,一心只想往前飞
  • 首页
  • 博客
    • 博客历史
    • 主题
    • 个人文集
  • 关于
    • 正在读的书
    • 作品归档
    • 2018作品归档
    • 联系我
  • 友情链接
  • 留言板
❄
❅
❆
❄
❅
❆
❄
❅
❆
❄
Front-End

React前后端数据绑定

Posted on 2016年10月31日 by 九九 / 1955 Views

React前后端数据绑定

目录

*1.上节回顾

*2.使用.NET MVC快速构建后端API

*3.React前端模板

*4.数据绑定

*5.在项目中引入bootstrap

*6.刷新数据

1.上节回顾

将React项目中css样式分离成单独的文件

本节需求:一个简单的电影列表展示。

2.使用.NET MVC快速构建后端API

如何使用.NET MVC创建后端API,在这里不再详细讨论。

新建MVC4项目RenderData

model.cs

public class Movies
{
  public Int64 Id { get; set; }
  public string Name { get; set; }
  public string Logo { get; set; }
  public Int64 UpdateId { get; set; }
  public DateTime UpdateDate { get; set; }
}

MovieController.cs

[HttpGet]
public ActionResult GetList()
{
  StreamReader sr = new StreamReader(Server.MapPath("/data/movielist.json"));
  return Content(sr.ReadToEnd());
}

[HttpGet]
public ActionResult OneMovie()
{
  StreamReader sr = new StreamReader(Server.MapPath("/data/onemovie.json"));
  return Content(sr.ReadToEnd());
}

movielist.json

{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "A",
      "logo": "../Img/1.jpg",
      "updateid": 0,
      "updatedate": "2016-10-26 00:00:00"
    },
    {
      "id": 2,
      "name": "B",
      "logo": "../Img/1.jpg",
      "updateid": 0,
      "updatedate": "2016-10-27 00:00:00"
    },
    {
      "id": 3,
      "name": "C",
      "logo": "../Img/1.jpg",
      "updateid": 0,
      "updatedate": "2016-10-28 00:00:00"
    },
    {
      "id": 4,
      "name": "D",
      "logo": "../Img/1.jpg",
      "updateid": 0,
      "updatedate": "2016-10-29 00:00:00"
    },
    {
      "id": 5,
      "name": "E",
      "logo": "../Img/1.jpg",
      "updateid": 0,
      "updatedate": "2016-10-30 00:00:00"
    },
    {
      "id": 6,
      "name": "F",
      "logo": "../Img/1.jpg",
      "updateid": 0,
      "updatedate": "2016-11-01 00:00:00"
    },
    {
      "id": 7,
      "name": "I",
      "logo": "../Img/1.jpg",
      "updateid": 0,
      "updatedate": "2016-11-02 00:00:00"
    }
  ]
}

OneMovie.json

{
  "success": true,
  "data": {
    "id": 1,
    "name": "A",
    "logo": "../Img/1.jpg",
    "updateid": 0,
    "updatedate": "2016-10-26 00:00:00"
  }
}

重新编译=>选中 Controllers =>右键 在浏览器中浏览:

我们得到2个api:

获取电影列表
http://localhost:43286/movie/getlist

获取一个电影的详细信息
http://localhost:43286/movie/onemovie

注意,需要给web.config配置上允许访问的标识,在这里我们允许任何前端直接请求api,以免出现跨域的报错。

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Methods" value="OPTIONS,POST,GET"/>
        <add name="Access-Control-Allow-Headers" value="x-requested-with"/>
        <add name="Access-Control-Allow-Origin" value="*" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
3.React前端模板

创建一个前端项目FrontEnd

文件夹结构如下:

project--
|
|--components
|       |
|       |--icon.jsx
|       |--movie.jsx
|       |--index.jsx
|
|--css
|   |--movie.css
|    
|--index.html
|--package.json
|--webpack.config.js

结合上节,我们制作一个简单的html静态页面:

module.html

<html>

<head>
    <title></title>
    <style>
        .movie {
            width: 200px;
            height: 80px;
        }

        .left {
            width: 100px;
            height: 80px;
            float: left;
        }

        .right {
            width: 100px;
            height: 80px;
            float: left;
        }

        .logo {
            width: 100%;
            height: 100%;
        }

        .logo span {
            width: 100px;
            text-align: center;
            margin-top: -15px;
            background-color: silver;
            position: absolute;
            font-size: 10pt;
            color: white;
            opacity: 0.8;
        }
    .intro{
      width: 100px;
      word-wrap: break-word;
      /* word-spacing: inherit; */
      /* display: block; */
      /* white-space: nowrap; */
      /* overflow: hidden; */
      /* text-overflow: ellipsis; */
    }
    </style>
</head>
<body>
  <div class="movie">
    <div class="left">
      <div class="logo">
        <img src="img/1.jpg" width="100" height="70" />
        <span>2012-01-01</span>
      </div>
    </div>
    <div class="right">
      <div class="name">aaaaa</div>
      <div class="intro">introintrointrointrointrointro</div>
    </div>
  </div>
</body>
</html>

效果图:

blog

参考上节知识,分离样式,css和组件jsx,这里直接上代码

icon.jsx

'use strict'
var React = require('react');
var DateFormat=require('../common/dateformat')

module.exports = React.createClass({
  displayName: 'Icon',
  render: function () {
    return (
      <div className="logo">
        <img src="" width="100" height="70" />
        <span>2012-01-01</span>
      </div>
    );
  }
});

movie.jsx

'use strict'
var React = require('react');
var Icon = require('./icon');
module.exports = React.createClass({
  displayName: 'Movie',
  render: function () {
    var movieshtml = this.state.movies.map(function (movie) {
      // 将movie传入
      return (
        <div className="movie" key={movie.id}>
          <div className="left">
            <Icon data={movie}></Icon>
          </div>
          <div className="right">
            <div className="name">{movie.name}</div>
            <div className="intro">{movie.updatedate}</div>
          </div>
        </div >
      )
    });
    return <div>{movieshtml}</div>
  }
});

index.jsx

'use strict'
var ReactDOM = require('react-dom');
var Icon = require('./icon');
var Movie = require('./movie');
ReactDOM.render(
  <div>
    <Movie></Movie>
  </div>,
  document.getElementById('content')
);

在movie.jsx中,

api返回的是一段json对象数组,然而我们需要在render中渲染出html列表返回到index.jsx中

在最初的index.jsx中,

this.state.movies.map(function (movie) {
  com = com + '<div className="movie" key={movie.id}>\
    <div className="left">\
      <Icon data={movie}></Icon>\
    </div>\
    <div className="right">\
      <div className="name">{movie.name}</div>\
      <div className="intro">{movie.updatedate}</div>\
    </div>\
  </div>';
})
return (
  { com }
)

使用html拼接,然而并不奏效,
console报错invariant.js:38 Uncaught Error: Movie.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.(…)

4.数据绑定

在修改中发现,map执行的遍历会在结果返回,将上面代码更新为:

movie.jsx

  var movieshtml = this.state.movies.map(function (movie) {
    // 将movie传入
    return (
      <div className="movie" key={movie.id}>
        <div className="left">
          <Icon data={movie}></Icon>
        </div>
        <div className="right">
          <div className="name">{movie.name}</div>
          <div className="intro">{movie.updatedate}</div>
        </div>
      </div >
    )
  });
  return <div>{movieshtml}</div>

由于icon.jsx保存了电影的信息,所以将{movie}传入Icon,放到data属性中。

<Icon data={movie}></Icon>

以便在icon.jsx中使用。

在icon.jsx中,我们需要绑定上电影信息(如果你用过angularjs1,这里的绑定会清晰,这里不再探讨为什么这么绑定,你可以参考我的angularjs的文章),
修改一下上面icon.jsx

  render: function () {
    var movie = this.props.data;
    var date = new Date(movie.updatedate);
    return (
      <div className="logo">
        <img src={movie.logo} width="100" height="70" />
        <span>{movie.updatedate,'yyyy-MM-dd'}</span>
      </div>
    );
  }

然而在module.html中,图片上的时间格式为yyyy-MM-dd,而目前api返回的时间格式为’yyyy-MM-dd HH:mm:ss’,
假设已经存在一个时间转换方法DateFormat。

所以上面return回的代码可以更新为

    return (
      <div className="logo">
        <img src={movie.logo} width="100" height="70" />
        <span>{DateFormat(movie.updatedate,'yyyy-MM-dd')}</span>
      </div>
    );

新建common/dateformat.jsx,我们将string字符串时间转换为yyyy-MM-dd格式:

dateformat.jsx

module.exports = function (date, format) {
  date = new Date(date);
  var year = date.getFullYear();
  var month = date.getMonth() + 1;
  var day = date.getDate();
  var hour = date.getHours();
  var minute = date.getMinutes();
  var second = date.getSeconds();
  var millisecond = date.getMilliseconds();
  // yyyy-MM-dd HH:mm:ss
  var str = '';
  // yyyy  yy
  if (new RegExp('y{4}').test(format) && new RegExp('y{2}').test(format)) {
    str = str + year.toString();
  }
  if (!new RegExp('y{4}').test(format) && new RegExp('y{2}').test(format)) {
    str = str + year.toString().substr(2, 3);
  }
  if (new RegExp('M{2}').test(format)) {
    str = str + '-' + (month < 10 ? ('0' + month.toString()) : month.toString());
  }
  if (new RegExp('d{2}').test(format)) {
    str = str + '-' + (day < 10 ? ('0' + day.toString()) : day.toString());
  }
  if (new RegExp('H{2}').test(format)) {
    str = str + ' ' + (hour < 10 ? ('0' + hour.toString()) : hour.toString());
  }
  if (new RegExp('m{2}').test(format)) {
    str = str + ':' + (minute < 10 ? ('0' + minute.toString()) : minute.toString());
  }
  if (new RegExp('s{2}').test(format)) {
    str = str + ':' + (second < 10 ? ('0' + second.toString()) : second.toString());
  }
  return str;
}

绑定完毕,我们在渲染的时候初始化一段数据,
在AngularJS1中,状态通常保存在$scope中,
而在react,状态通常保存在state中。

阮一峰在React 入门实例教程将到组件的生命周期包括三个状态:

组件的生命周期分成三个状态:
• Mounting:已插入真实 DOM
• Updating:正在被重新渲染
• Unmounting:已移出真实 DOM
React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数。
• componentWillMount()
• componentDidMount()
• componentWillUpdate(object nextProps, object nextState)
• componentDidUpdate(object prevProps, object prevState)
• componentWillUnmount()
此外,React 还提供两种特殊状态的处理函数。
• componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
• shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用

给movie.jsx初始化状态,添加以下代码:

  getInitialState: function () {
    return {
      movies: [{
        id: 1,
        name: "A",
        logo: "../Img/1.jpg",
        updateid: 0,
        updatedate: "2016-10-26 00:00:00"
      }
      ]
    };
  },
  componentDidMount: function () {
  },

cd到前端代码根目录,CMD运行 > npm start

打开 http://localhost:8889/
一个图文简介电影介绍已经被显示的浏览器上。

效果图:

blog

而我们要获得一个列表,在componentDidMount方法中添加ajax请求数据,在页面dom被渲染之后isMounted更新数据:

  componentDidMount: function () {
    $.get("http://localhost:43286/Movie/getlist", function (result) {
      var movies = JSON.parse(result).data;
      if (this.isMounted()) {
        this.setState({
          movies: movies
        });
        // console.log(this);
      }
    }.bind(this)); //需要绑定一下this,why?
  }

刷新页面,数据已经更新。

效果图:

blog

*5.在项目中引入bootstrap

修改配置文件,这里可以参考第三节(上一节):(React引入样式)(http://blog.99diary.com/2016/10/28/react引入样式/) 引入bootstrap样式Panels

修改movie.jsx

  render: function () {
    var movieshtml = this.state.movies.map(function (movie) {
      // 将movie传入
      return (
        // 在这里key需要放在list top-level标签上,否则报错
        // react-with-addons.js:22809Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using <div>. See https://fb.me/react-warning-keys for more information.
        <div className="panel panel-primary" key={movie.id}>
          <div className="movie panel-body">
            <div className="left">
              <Icon data={movie}></Icon>
            </div>
            <div className="right">
              <div className="name">{movie.name}</div>
              <div className="intro">{movie.updatedate}</div>
            </div>
          </div >
        </div>
      )
    });
    return <div>{movieshtml}</div>
  }

效果图:

blog

可见bootstrap已经被应用成功。

注:这里不考虑美观。

6.刷新数据

这里可以参考第二节:react中简单的数据绑定与事件

在项目中新建一个组件:刷新按钮,

refreshbutton.jsx

'use strict'
var React = require('react');
module.exports = React.createClass({
  displayName: 'RefreshButton',
  refresh: function () {
    console.log(this);
    $.get("http://localhost:43286/Movie/getnewlist", function (result) {
      var movies = JSON.parse(result).data;
      this.setState({
        movies: movies
      });
      console.log(this);
      // if (this.isMounted()) {
      // }
    }.bind(this));
  },
  render: function () {
    // react-with-addons.js:22809Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using <div>. 
    // See https://fb.me/react-warning-keys for more information.
    return (
      <button type="button" key="refreshbutton" className="btn btn-xs btn-info" onClick={this.refresh}>Refresh</button>
    );
  }
});

然而,这并不能解决问题,我们要解决的是独立组件之间的通信。

这个问题可能会在下章单独解决。

本节源码地址(import data)

MVC, React
九九
过去的我们,现在的自己,往事,终会随风而逝。 View all posts by 九九 →

Post navigation

Older post
React引入样式
Newer post
React事件传递

标签云

2019ncov Android ASP.NET Baby C# C/C++ CSS Div DX11 flask front-end GAE Git Java JJProject JS Life MSSQL MVC OpenSource Oracle Python React React-Native Software Tools Vue Webpack Website Window WP7 乱记 十年旧梦 天气 宝宝成长日记 小说 工作 情感 故障 散文 日记 网新实训笔记 花落梧桐 诗间集 转载

时光机

  • 2023年3月
  • 2023年2月
  • 2022年12月
  • 2022年4月
  • 2022年3月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年5月
  • 2019年12月
  • 2019年10月
  • 2019年9月
  • 2019年6月
  • 2019年5月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年3月
  • 2018年2月
  • 2018年1月
  • 2017年11月
  • 2017年10月
  • 2017年9月
  • 2017年7月
  • 2017年3月
  • 2017年1月
  • 2016年12月
  • 2016年11月
  • 2016年10月
  • 2016年7月
  • 2016年3月
  • 2016年2月
  • 2016年1月
  • 2015年12月
  • 2015年11月
  • 2015年10月
  • 2015年9月
  • 2015年8月
  • 2015年7月
  • 2015年4月
  • 2015年3月
  • 2015年2月
  • 2015年1月
  • 2014年12月
  • 2014年11月
  • 2014年10月
  • 2014年9月
  • 2014年8月
  • 2014年7月
  • 2014年6月
  • 2014年5月
  • 2014年4月
  • 2014年3月
  • 2014年2月
  • 2014年1月
  • 2013年12月
  • 2013年11月
  • 2013年10月
  • 2013年9月
  • 2013年8月
  • 2013年7月
  • 2013年6月
  • 2013年5月
  • 2013年4月
  • 2013年3月
  • 2013年1月
  • 2012年11月
  • 2012年10月
  • 2012年9月
  • 2012年8月
  • 2012年7月
  • 2012年6月
  • 2012年5月
  • 2012年4月
  • 2012年3月
  • 2012年2月
  • 2012年1月
  • 2011年12月
  • 2011年11月
  • 2011年10月
  • 2011年9月
  • 2011年8月
  • 2011年6月
  • 2011年5月
  • 2011年4月
  • 2011年3月
  • 2011年2月
  • 2010年12月
  • 2010年11月
  • 2010年10月
  • 2010年9月
  • 2010年8月
  • 2010年6月
  • 2010年5月
  • 2010年2月
  • 2010年1月
  • 2009年12月
  • 2009年11月
  • 2009年10月
  • 2009年9月
  • 2009年8月
  • 2009年7月
  • 2009年6月
  • 2009年5月
  • 2009年4月
  • 2009年3月
  • 2009年2月
  • 2009年1月
  • 2008年8月
  • 2008年6月
  • 2008年5月
  • 2008年4月
  • 2008年2月
  • 2007年11月
  • 2007年8月
  • 2007年6月
  • 2007年5月
  • 2007年4月
  • 2007年3月
  • 2007年2月
  • 2007年1月
  • 2006年10月
  • 2006年8月
© 2006 - 2023 久久日记本
Powered by WordPress | Theme: Graphy for 99diary