React---前端JS library

来源:互联网 发布:淘宝 韩国 模特 编辑:程序博客网 时间:2024/06/05 18:17

想要了解如何在spring中集成react可以看我另一篇博客
spring集成react


今天想写一个关于React的blog,在接下来还是会继续更新的,把构建的所学所感总结一下:

React是一个js库,并不是一个前端框架,更像是一个工具。react的思想比较好:以组件(component)的形式来构建html,构建完成后可以render到html的DOM中。组件可以被嵌套、被重用。当然react的性能优化主要体现在virtual DOM上,即写的这些个组件并没有最初就插入了真实DOM,而是以一种内存数据(virtual DOM)形式存在(因此会性能提高),当组件的状态因前端客户的操作(比如点击了一次button)而发生改变时,这时候就会进行一次virtual DOM 与上一次DOM(已插入)对比,仅仅更新变化的部分,此为性能提升第二步。

React的使用:
并不需要什么安装,仅仅是在Html页面中引入便罢了

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>React demo</title><script src="../Resources/react.js"></script><script src="../Resources/react-dom.js"></script><script src="../Resources/browser.min.js"></script></head>

这里说明一下: 之前的JSXTransformer已经被facebook等deprecated(目前的CDN貌似已经找不到了),取而代之的是browser.js,即将JSX(JavaScript与html混写的格式)转化成纯的js。其实它们的作用是一样的,这里我下载下来并引入了本地,这里略微变态的是假如你选择的browser.min.js版本不对,可能会抛错,解决方法参考[reactjs Cannot read property ‘keys’ of undefined

Ask](http://stackoverflow.com/questions/36672007/reactjs-cannot-read-property-keys-of-undefined)

把写的代码贴一下:

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>React demo</title><script src="../Resources/react.js"></script><script src="../Resources/react-dom.js"></script><script src="../Resources/browser.min.js"></script></head><body><div id="hello"></div><script type="text/babel"> //这里是text/babel//第一个例子ReactDOM.render(    <h1>Hello, world</h1>, //组件    document.getElementById('hello') //要渲染到的DOM位置);var Greet = React.createClass({ //第二个例子 生成一个新的组件    render: function() {        return <h1>Hello {this.props.name}</h1> //变量用{}包括    }});ReactDOM.render(    <Greet name="fujian" />,    document.getElementById('hello'));//第三个例子var InputState = React.createClass({    getInitialState: function() { //组件的初始state        return {enable: false};    },     handleClick: function() { //触发该方法会做的事情        this.setState({enable: !this.state.enable});    },    render: function() { //渲染        return (            <p>                <input type="text" disabled={this.state.enable} />                <button onClick={this.handleClick}>Change State</button>            </p>        );    }});ReactDOM.render(    <InputState />,    document.getElementById('hello'));//第四个例子var Hello = React.createClass({    getInitialState: function() {        return {            opacity: 1.0        };    },    componentDidMount: function() { //组件状态插入完成后触发该函数        this.timer = setInterval(function() { //该组件的timer属性            var opacity = this.state.opacity;            opacity -= .05;            if(opacity < 0.1) {                opacity = 1.0;            }            this.setState({                opacity:opacity            });        }.bind(this), 100); //每隔100毫秒要做以上的事情    },    render: function() {        return (            <div style={{opacity: this.state.opacity}}> //将组件的opacity属性赋值给div的css(可见性)                Hello {this.props.name}            </div>        );    }});ReactDOM.render(    <Hello name="world" />,    document.getElementById('hello'));//第五个例子 用来演示不同组件的嵌套,Page组件中嵌套了Search,难度不大var Search= React.createClass({    render: function() {        return (            <div>                {this.props.searchType}:<input type="text" />                <button>Search</button>            </div>        );    }});var Page = React.createClass({    render: function(){        return (            <div>                <h1>Welcome!</h1>                <Search searchType="Title" />                <Search searchType="Content" />            </div>        );    }});ReactDOM.render(    <Page />,    document.getElementById('hello'));</script></body></html>

20170323更新
React的组件化再次触动了我,这种组织前端页面的思想感觉就像当时感觉java的面向对象一般令人兴奋,后台负责返回json格式的json给前端,前端用react去组装显示这些数据,下边这个栗子是官网上的demo,可以很明显的体会到react的好用之处,自上而下 组件从小到大,依次被嵌套,最后被渲染,棒极了!

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Demo1</title><script src="../Resources/bootstrap.min.css"></script><script src="../Resources/react-with-addons.js"></script><script src="../Resources/react-dom.js"></script><script src="../Resources/browser.js"></script><style type="text/css">body {    padding: 5px}</style></head><body><div id="container"></div><script type="text/babel">//产品的分类组件var ProductCategoryRow =  React.createClass({    render: function(){        return (<tr><th colSpan="2">{this.props.category}</th></tr>);    }});//产品的具体信息组件var ProductRow = React.createClass({        render:function(){            var name = this.props.product.stocked? this.props.product.name : <span style={{color:'red'}}>{this.props.product.name}</span>;            return(<tr><td>{name}</td><td>{this.props.product.price}</td></tr>);        }    });//产品table,包括若干之前两个组件var ProductTable = React.createClass({    render: function() {        var rows = [];        var lastCategory = null;        this.props.products.forEach(function(product){            if(product.category !== lastCategory) {                rows.push(<ProductCategoryRow category={product.category} key={product.category} />);            }            rows.push(<ProductRow product={product} key={product.name} />);            lastCategory = product.category;        });        return(<table><thead>                        <tr>                            <th>Name</th>                            <th>Price</th>                        </tr>                        </thead>                        <tbody>{rows}</tbody>                </table>            );    }});//查询组件,和产品table组件是平行关系var SearchBar = React.createClass({    render: function(){        return (<form>                    <input type="text" placeholder="Search..." />                    <p>                        <input type="checkbox" />                        {' '}                        Only show  products in stock                    </p>                </form>        );    }});//最外层的组件var FilterableProductTable = React.createClass({    render: function(){        return (            <div>                <SearchBar />                <ProductTable products={this.props.products} />            </div>        );    }});var PRODUCTS = [  {category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},  {category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},  {category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},  {category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},  {category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},  {category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}];//将嵌套组件的最外层组件用来渲染页面DOMReactDOM.render(    <FilterableProductTable products={PRODUCTS} />,    document.getElementById('container'));</script></body></html>

——————————-更新线—————————
2017/03/25
上边的栗子出自:
tinking in react

里边提到这么一句话:

To build a static version of your app that renders your data model, you’ll want to build components that reuse other components and pass data using props. props are a way of passing data from parent to child. If you’re familiar with the concept of state, don’t use state at all to build this static version. State is reserved only for interactivity, that is, data that changes over time. Since this is a static version of the app, you don’t need it.

这里points有:

  • 属性props是从父节点传递数据从子节点的一种方式
  • 当你构建页面静态部分时不要考虑用state,使用状态是为了交互而用,也就是说,你构建的页面仅仅是为了展示数据,那就不用考虑使用state了。

到这里,其实主要突出了props的一大用处,即借用属性来传递数据,包括原始的和后来分解的,下面的话,就要接触React的另一大特性:state


如何选择组件的state?文档里给出了三个不为state的标准

  • Is it passed in from a parent via props? If so, it probably isn’t state.
  • Does it remain unchanged over time? If so, it probably isn’t state.
  • Can you compute it based on any other state or props in your component? If so, it isn’t state.

  • 它是否从父节点通过属性props传递而来,是则不为state

  • 它是否自始至终不发生变化,是则不为state
  • 它是否可以根据任意state和props来计算,是则不为state

结合上边的例子,state为:

  • The search text the user has entered
  • The value of the checkbox

那么该如何添加这些state以及哪些组件应该拥有这些states呢?
通用性的理论解释这里不贴了,直接拿上边那个栗子解释:

  • ProductTable needs to filter the product list based on state and SearchBar needs to display the search text and checked state.
  • The common owner component is FilterableProductTable.
  • It conceptually makes sense for the filter text and checked value to live in FilterableProductTable

Cool, so we’ve decided that our state lives in FilterableProductTable. First, add a getInitialState() method to FilterableProductTable that returns {filterText: ”, inStockOnly: false} to reflect the initial state of your application. Then, pass filterText and inStockOnly to ProductTable and SearchBar as a prop. Finally, use these props to filter the rows in ProductTable and set the values of the form fields in SearchBar.

以上就是state的重点了,大体意思是:

  • 产品table需要根据state来展示产品列表,searchBar需要根据state来展示用户输入的text以及checkbox的选择状态
  • FilterableProductTable组件拥有以上这两个需要state的子组件

    酷哇! 所以我们就选择把我们的state放到FilterableProductTable组件中喽,首先就是添加getInitialState()方法来初始化filterText和inStockOnly({filterText: ”, inStockOnly: false});然后将这两个stats作为props传递给ProductTable和SearchBar组件;最后使用这些props在ProductTable中过滤行,在SearchBar中展示。


根据之前的栗子再把有关state的代码补充完整:
这里只标注了和前边的例子对比变化的部分

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Demo1</title><script src="../Resources/bootstrap.min.css"></script><script src="../Resources/react-with-addons.js"></script><script src="../Resources/react-dom.js"></script><script src="../Resources/browser.js"></script><style type="text/css">body {    padding: 20px}</style></head><body><div id="container"></div><script type="text/babel">var ProductCategoryRow =  React.createClass({    render: function(){        return (<tr><th colSpan="2">{this.props.category}</th></tr>);    }});var ProductRow = React.createClass({        render:function(){            var name = this.props.product.stocked? this.props.product.name : <span style={{color:'red'}}>{this.props.product.name}</span>;            return(<tr><td>{name}</td><td>{this.props.product.price}</td></tr>);        }    });var ProductTable = React.createClass({    render: function() {        var rows = [];        var lastCategory = null;        this.props.products.forEach(function(product){        //step3:state传递给props后,根据这些state来进行业务逻辑控制            if(product.name.indexOf(this.props.filterText) === -1 || (!product.stocked && this.props.inStockOnly)) {                return;            }            if(product.category !== lastCategory) {                rows.push(<ProductCategoryRow category={product.category} key={product.category} />);            }            rows.push(<ProductRow product={product} key={product.name} />);            lastCategory = product.category;        }.bind(this)); //bind()暂时没弄明白        return(<table>                    <thead>                        <tr>                            <th>Name</th>                            <th>Price</th>                        </tr>                    </thead>                    <tbody>                        {rows}                    </tbody>                </table>            );    }});var SearchBar = React.createClass({    render: function(){        return (<form>                    <input type="text" placeholder="Search..."  value={this.props.filterText} />                    <p>                        <input type="checkbox"  checked={this.props.inStockOnly} />                        {' '}                        Only show  products in stock                    </p>                </form>        );    }});var FilterableProductTable = React.createClass({    getInitialState: function() { // step1:添加getInitialState() 方法来初始化state        return {            filterText: '',            inStockOnly: false        };    },    render: function(){        return (            <div>                <SearchBar // step2:将state 传递给props                    filterText = {this.state.filterText}                    inStockOnly = {this.state.inStockOnly}                 />                <ProductTable  // step2:将state传递给props                    products={this.props.products}                     filterText = {this.state.filterText}                    inStockOnly = {this.state.inStockOnly}                />            </div>        );    }});var PRODUCTS = [  {category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},  {category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},  {category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},  {category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},  {category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},  {category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}];ReactDOM.render(    <FilterableProductTable products={PRODUCTS} />,    document.getElementById('container'));</script></body></html>

以上并不是结束,上边的栗子只能手动去更改intialState的值然后刷新页面,这并不符合真正的需求,比如把getInitialState方法中的inStockOnly改成true,刷新页面

接着引用:

If you try to type or check the box in the current version of the example, you’ll see that React ignores your input. This is intentional, as we’ve set the value prop of the input to always be equal to the state passed in from FilterableProductTable.

就是你无法输入或者check,因为我们在定义searchBar组件时,input和checkbox的属性值一直等于传递过来的state

而我们想要的呢?

Let’s think about what we want to happen. We want to make sure that whenever the user changes the form, we update the state to reflect the user input.

即无论user输入什么,我们都将根据输入和check来实时更新state


接下来是大招了,目的是为了当user输入或者check时实时改变展示的数据……

这里主要主要的核心技术无非就是回调函数(callback)了,即searchBar组件根据user的输入实时调用FilterableProductTable 组件的callback函数,callback函数里setState()从而根据用户的输入将组件的state改变,后边进行的就是前边所讲的了。这样一来,就能实时根据user输入来改变数据显示了。

FilterableProductTable will pass a callback to SearchBar that will fire whenever the state should be updated. We can use the onChange event on the inputs to be notified of it. And the callback passed by FilterableProductTable will call setState(), and the app will be updated.

其实回调在好多地方都有用处,callback掌握的不是很好,有机会专门写一篇关于calllback的blog。

将代码贴一下,只注释改变的部分:

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Demo1</title><script src="../Resources/bootstrap.min.css"></script><script src="../Resources/react-with-addons.js"></script><script src="../Resources/react-dom.js"></script><script src="../Resources/browser.js"></script><style type="text/css">body {    padding: 20px}</style></head><body><div id="container"></div><script type="text/babel">var ProductCategoryRow =  React.createClass({    render: function(){        return (<tr><th colSpan="2">{this.props.category}</th></tr>);    }});var ProductRow = React.createClass({        render:function(){            var name = this.props.product.stocked? this.props.product.name : <span style={{color:'red'}}>{this.props.product.name}</span>;            return(<tr><td>{name}</td><td>{this.props.product.price}</td></tr>);        }    });var ProductTable = React.createClass({    render: function() {        var rows = [];        var lastCategory = null;        this.props.products.forEach(function(product){            if(product.name.indexOf(this.props.filterText) === -1 || (!product.stocked && this.props.inStockOnly)) {                return;            }            if(product.category !== lastCategory) {                rows.push(<ProductCategoryRow category={product.category} key={product.category} />);            }            rows.push(<ProductRow product={product} key={product.name} />);            lastCategory = product.category;        }.bind(this));        return(<table>                    <thead>                        <tr>                            <th>Name</th>                            <th>Price</th>                        </tr>                    </thead>                    <tbody>                        {rows}                    </tbody>                </table>            );    }});var SearchBar = React.createClass({    handleChange: function(){ //step2:当触发handleChange时 将refs的两个状态值作为callback的两个参数,进而回调改变FilterableProductTable 组件的state的值        this.props.onUserInput(            this.refs.filterTextInput.value,            this.refs.inStockOnlyInput.checked        );    },      render: function(){        return (<form>                    <input type="text" placeholder="Search..."  value={this.props.filterText} ref="filterTextInput" onChange={this.handleChange}/>                    <p>                        <input type="checkbox"  checked={this.props.inStockOnly} ref="inStockOnlyInput" onChange={this.handleChange}/> //step1:onChange实时监控user输入并触发handleChange                        {' '}                        Only show  products in stock                    </p>                </form>        );    }});var FilterableProductTable = React.createClass({    getInitialState: function() {        return {            filterText: '',            inStockOnly: false        };    },//step3:回调,根据SearchBar组件传过来的两个参数用setState来改变state的值,接下来重新进行业务逻辑处理并渲染    handleUserInput: function(filterText, inStockOnly) {        this.setState({            filterText: filterText,            inStockOnly: inStockOnly        });    },    render: function(){        return (            <div>                <SearchBar                    filterText = {this.state.filterText}                    inStockOnly = {this.state.inStockOnly}                    onUserInput = {this.handleUserInput} //将callback作为searchBar的属性                 />                <ProductTable                     products={this.props.products}                     filterText = {this.state.filterText}                    inStockOnly = {this.state.inStockOnly}                />            </div>        );    }});var PRODUCTS = [  {category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},  {category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},  {category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},  {category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},  {category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},  {category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}];ReactDOM.render(    <FilterableProductTable products={PRODUCTS} />,    document.getElementById('container'));</script></body></html>

写的不太好,也是想便于自己理解,以后得在实践中多多使用

0 0