React学习2

来源:互联网 发布:常见的网络进攻形式 编辑:程序博客网 时间:2024/06/11 18:13

React本质上是一个”状态机”,可以帮助开发者管理复杂的随着时间而变化的状态。React只关心两件事:
1.更新DOM
2.响应事件
在每次状态改变时,使用JavaScript重新渲染整个页面会异常慢,这应该归咎于读取和更新DOM的性能问题。React运用一个虚拟的DOM实现了一个非常强大的渲染系统,在React中对DOM只更新不读取
React以渲染函数为基础,这些函数读入当前的状态,将其转换为目标页面上的一个虚拟表现。只要React被告知状态有变化(更新组件的内部状态会触发组件重绘),它就会重新运行这些函数,计算出页面的一个新的虚拟表现,接着自动地把结果转换成必要的DOM更新来反映新的表现(React使用了非常高效的算法,计算出虚拟页面当前版本和新版本间的差异,基于这些差异对DOM进行必要的最少更新)。
React赢就赢在最小化了重绘,并避免了不必要的DOM操作。

ReactDOM.render

ReactDOM.render 是 React 的最基本方法(渲染函数),用于将模板转为 HTML 语言,并插入指定的 DOM 节点。

ReactDOM.render(  <h1>Hello, React!</h1>,  document.getElementById('example'));

上面代码将一个 h1 标题,插入 example 节点
render方法需注意的几点:
1.只能通过this.props和this.state访问数据
2.可以返回null、false或者任何React组件
3.只能出现一个顶级组件(不能返回一组元素)
4.必须纯净,意味着不能改变组件的状态或者修改DOM的输出。
render方法返回的结果不是真正的DOM,而是一个虚拟的表现,React随后会把它和 真是的DOM(内存中的DOM)做对比,来判断是否有必要。

React JSX

React 使用 JSX 来替代常规的 JavaScript。JSX即JavaScript XML,是一种在React组件内部构建标签的类XML语法。
JSX的优点:

  • 允许使用熟悉的语法来定义HTML元素树
  • 提供更加语义化且易懂的标签(将传统的HTML标签封装成React组件),我们就可以像使用HTML标签一样使用这个组件。
  • 程序结构更容易被直观化(在函数作用域内,使用JSX语法的代码与原生JavaScript相比,其标签的意图变得更加直观,可读性也更高)。
  • 抽象了React Element的创建过程
  • 可以随时掌控HTML标签以及生成这些标签的代码
  • 是原生的JavaScript

使用动态值

JSX将两个花括号之间的内容{…}渲染为动态值。花括号指明了一个JavaScript上下文环境–你在花括号中放入的任何东西都会被进行求值,得到的结果被渲染为标签中的若干节点。

JavaScript 表达式

在 JSX 中使用 JavaScript 表达式。表达式要写在花括号 {} 中。实例如下:

ReactDOM.render(    <div>      <h1>{1+1}</h1>    </div>    ,    document.getElementById('example'));

在 JSX 中不能使用 if-else 语句,但可以使用三元运算表达式来替代。示例如下:

ReactDOM.render(    <div>      <h1>{i == 1 ? 'True' : 'False'}</h1>    </div>    ,    document.getElementById('example'));

样式

React 推荐使用内联样式,React 会在指定元素数字后自动添加 px 。示例如下:

var myStyle = {    fontSize: 30,    color: '#FF0000'};ReactDOM.render(    <h1 style = {myStyle}>Hello World</h1>,    document.getElementById('example'));

注释

注释需要写在花括号中,实例如下:

ReactDOM.render(    <div>    <h1>React学习</h1>    {/*注释...*/}    </div>,    document.getElementById('example'));

数组

JSX 允许在模板中插入数组,数组会自动展开所有成员:

var arr = [  <h1>Hello React</h1>,  <h2>Hello React Native</h2>,];ReactDOM.render(  <div>{arr}</div>,  document.getElementById('example'));

非DOM属性

key

key是一个可选的唯一标识符。在程序运行的过程中,一个组件可能会在组件树中调整位置,比如当用户在进行搜索操作时,或者当一个列表中的物品被增加、删除时。当这些情况发生时,组件可能并不需要被销毁并重新创建。
通过给组件设置一个独一无二的键,并确保它在一个渲染周期中保持一致,使得React能够更智能地决定应该重用一个组件,还是销毁并重新创建一个组件,进而提升渲染性能。当两个已经存在在于DOM中的组件交换位置时,React能够匹配对应的键并进行相应的移动,且不需要完全重新渲染DOM。

ref

ref允许父组件在render方法之外保持对子组件的一个引用。
在JSX中,你可以通过在属性中设置期望的引用名来定义一个引用。

render:function(){    return <div>    <input ref="myInput" />    </div>;}

这样一来,我们就可以在组件中的任何地方使用this.refs.myInput获取这个引用了。通过引用获取到的这个对象被称为支持实例。它并不是真正的DOM,而是React在需要时用来创建DOM的一个描述对象。可以使用this.refs.myInput.getDOMNode()访问真实的DOM节点。

HTML 标签 vs React 组件

React 可以渲染 HTML 标签 (strings) 或 React 组件 (classes)。

  • 要渲染 HTML 标签,只需在 JSX 里使用小写字母的标签名。
var myDivElement = <div className="foo" />;ReactDOM.render(myDivElement, document.getElementById('example'));
  • 要渲染 React 组件,只需创建一个大写字母开头的本地变量。
var MyComponent = React.createClass({/*...*/});var myElement = <MyComponent someProperty={true} />;ReactDOM.render(myElement, document.getElementById('example'));

React 的 JSX 使用大、小写的约定来区分本地组件的类和 HTML 标签。
注意:
由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。作为替代,React DOM 使用 className 和 htmlFor 来做对应的属性。

React 组件

在传统HTML中,元素是构成页面的基础单元,但在React中,构成页面的基础单元是React 组件。可以把React 组件理解成混入了Javascript表达能力的HTML元素。实际上写React 代码主要就是构建组件,就像编写HTML文档时使用元素一样。
Demo:

var HelloMessage = React.createClass({  render: function() {    return <h1>Hello {this.props.name}</h1>;  }});ReactDOM.render(  <HelloMessage name="React" />,  document.getElementById('example'));

这里使用React.createClass 方法用于生成一个组件类 HelloMessage。
<HelloMessage /> 实例组件类并输出信息。
如果需要向组件传递参数,可以使用 this.props 对象
注意:

  • 原生 HTML 元素名以小写字母开头,而自定义的 React 类名以大写字母开头,比如 HelloMessage 不能写成 helloMessage。除此之外还需要注意组件类只能包含一个顶层标签,否则也会报错。
  • 在添加属性时, class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。

React State(状态)

React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
以下Demo中创建了 LikeButton 组件,getInitialState 方法用于定义初始状态,也就是一个对象,这个对象可以通过 this.state 属性读取。当用户点击组件,导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件

注:this.setState 方法仅仅是把传入的对象合并到已有的state对象。永远不要尝试通过setState或者replaceState以外的方式去修改state对象,因为会导致无法通知React是否需要重新渲染组件。
Demo:

<!DOCTYPE html><html><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <title>react state</title></head><body>    <div id="example"></div>    <script type="text/javascript" src="../build/react.js"></script>    <script type="text/javascript" src="../build/react-dom.js"></script>    <script type="text/javascript" src="../build/browser.min.js"></script>    <script type="text/babel">    var LikeButton = React.createClass({        getInitialState:function(){            return {liked:true};        },        handleClick:function(event){            this.setState({liked:!this.state.liked});        },        render:function(){            var text = this.state.liked ? '喜欢':'不喜欢';            return (            <p onClick = {this.handleClick}>You {text} this(点击切换状态)</p>                );        }    });        ReactDOM.render(        <LikeButton/>,        document.getElementById("example")        );    </script></body></html>

从用户输入到更新用户界面:
1.在React组件上绑定事件处理器
2.在事件处理器当中更新组件的内部状态。组件状态的更新会触发重绘。
3.实现组件的render函数用来渲染this.state的数据
当组件里的按钮被点击时,触发 handleClick 函数:

  • liked 状态被改变
  • React 重新渲染虚拟 DOM
  • 新老虚拟 DOM 进行对比
  • React 识别出变化的部分并渲染到浏览器(只更新变化的部分)

React Props

state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。
Demo:
这个小例子组合使用了 state 和 props 。在父组件中设置了 state, 并通过在子组件上使用 props 将其传递到子组件上。在 render 函数中, 我们设置 name 和 site 来获取父组件传递过来的数据。子组件与其父组件通信的最简单方式就是使用属性(props)。

<!DOCTYPE html><html><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <title>state和props</title></head><body>    <div id="example"></div>    <script type="text/javascript" src="../build/react.js"></script>    <script type="text/javascript" src="../build/react-dom.js"></script>    <script type="text/javascript" src="../build/browser.min.js"></script>    <script type="text/babel">        var Websites = React.createClass({            getInitialState:function(){                return {                    name:"百度一下",                    site:"http://www.baidu.com"                };            },            render:function(){                return (                    <div>                    <Name name = {this.state.name}/>                    <Link site = {this.state.site}/>                    </div>                );            }        });        var Name = React.createClass({            render:function(){                return (                    <h1>{this.props.name}</h1>                    );            }        });        var Link =React.createClass({            render:function(){                return(                    <a href = {this.props.site}>{this.props.site}</a>                );            }        });        ReactDOM.render(            <Websites />,            document.getElementById("example")        );    </script></body></html>

React 组件生命周期

组件的生命周期可分成三个状态:

  • Mounting:已插入真实 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真实 DOM

React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数:

  • componentWillMount() 在渲染前调用,在客户端也在服务端。
  • componentDidMount() 在第一次渲染后调用,只在客户端。
  • componentWillUpdate() 在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用
  • componentDidUpdate() 在组件完成更新后立即调用。在初始化时不会被调用。
  • componentWillUnmount() 在组件从 DOM 中移除的时候立刻被调用。

React 的两种特殊状态的处理函数:

  • componentWillReceiveProps():已加载组件收到新的参数时调用
  • shouldComponentUpdate():返回一个布尔值。在组件接收到新的props或者state时被调用,判断是否重新渲染组件,可以在你确认不需要更新组件时可以将其设为false。
    Demo:
<!DOCTYPE html><html><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <title>组件生命周期</title></head><body>    <div id="example"></div>    <script type="text/javascript" src="../build/react.js"></script>    <script type="text/javascript" src="../build/react-dom.js"></script>    <script type="text/javascript" src="../build/browser.min.js"></script>    <script type="text/babel">        var Button = React.createClass({            getInitialState:function(){                return {                data:0                };            },            setNumber:function(){                this.setState({                data:this.state.data+1                });            },            render:function(){                return (                <div>                    <button onClick = {this.setNumber}>增加</button>                    <Content myNumber = {this.state.data}/>                </div>                );            }        })        var Content = React.createClass({            componentWillMount:function() {                  console.log('Component WILL MOUNT!')              },              componentDidMount:function() {                   console.log('Component DID MOUNT!')              },              componentWillReceiveProps:function(newProps) {                    console.log('Component WILL RECIEVE PROPS!')              },              shouldComponentUpdate:function(newProps, newState) {                    return true;              },              componentWillUpdate:function(nextProps, nextState) {                    console.log('Component WILL UPDATE!');              },              componentDidUpdate:function(prevProps, prevState) {                    console.log('Component DID UPDATE!')              },              componentWillUnmount:function() {                     console.log('Component WILL UNMOUNT!')              },              render:function(){                return (                    <div>                        <h1>{this.props.myNumber}</h1>                    </div>                );              }        });        ReactDOM.render(            <Button />,            document.getElementById("example")        );    </script></body></html>

React AJAX

React 组件的数据可以通过 componentDidMount 方法中的 Ajax 来获取,当从服务端获取数据库可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI。
当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求。
Demo:
获取 Github 用户最新 gist 共享描述

<!DOCTYPE html><html><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <title>reactAjax</title></head><body>    <div id="example"></div>    <script type="text/javascript" src="build/react.js"></script>    <script type="text/javascript" src="build/react-dom.js"></script>    <script type="text/javascript" src="build/browser.min.js"></script>    <script type="text/javascript" src="build/jquery.min.js"></script>    <script type="text/babel">        var UserGist = React.createClass({            getInitialState:function(){                return {                    username:'',                    lastGistUrl:''                };            },            componentDidMount:function(){                this.serverRequest = $.get(this.props.source,function(data){                    var lastGist = data[0];                    this.setState({                        username:lastGist.owner.login,                        lastGistUrl:lastGist.html_url                    });                }.bind(this));            },            componentWillUnmount:function(){                this.serverRequest.abort();            },            render:function(){                return (                    <div>                        <h1>{this.state.username}用户最新的 Gist 共享地址:</h1>                        <a href={this.state.lastGistUrl}>{this.state.lastGistUrl}</a>                    </div>                );            }        });        ReactDOM.render(            <UserGist source = "https://api.github.com/users/octocat/gists"/>,            document.getElementById("example")        );    </script></body></html>

React 表单与事件

Demo1:
这里创建了两个组件,子组件和父组件
onChange 方法将触发 state 的更新并将更新的值传递到子组件的输入框的 value 上来重新渲染界面。
这里需要在父组件通过创建事件句柄 (handleChange) ,并作为属性 (这里是upDataState) 传递到子组件上。

<!DOCTYPE html><html><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <title>react事件和表单</title></head><body>    <div id="example"></div>    <script type="text/javascript" src="../../build/react.js"></script>    <script type="text/javascript" src="../../build/react-dom.js"></script>    <script type="text/javascript" src="../../build/browser.min.js"></script>    <script type="text/babel">    var Content = React.createClass({        render:function(){            return (                <div>                <input type="text" value = {this.props.myData} onChange = {this.props.upDataState}/>                <h1>{this.props.myData}</h1>                </div>            );        }    });        var HelloMessage=React.createClass({        getInitialState:function(){            return {value:'hello react'};        },        handleChange:function(event){            this.setState({value:event.target.value});        },        render:function(){            var value=this.state.value;            return (                <div>                <Content myData = {value} upDataState = {this.handleChange}/>                </div>                );    }    });    ReactDOM.render(        <HelloMessage />,        document.getElementById('example')        );    </script></body></html>

当从子组件中更新父组件的 state 时,你需要在父组件通过创建事件句柄 (handleChange) ,并作为 属性 (updataState) 传递到你的子组件上。
Demo2:

<!DOCTYPE html><html><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <title>react事件与表单</title></head><body>    <div id="example"></div>    <script type="text/javascript" src="../../build/react.js"></script>    <script type="text/javascript" src="../../build/react-dom.js"></script>    <script type="text/javascript" src="../../build/browser.min.js"></script>    <script type="text/babel">    var Content = React.createClass({        render:function(){            return (            <div>            <button onClick = {this.props.updataState}>点击改变</button>            <h1>{this.props.myData}</h1>            </div>            );        }    });             var HelloMessage = React.createClass({                getInitialState:function(){                    return {                        value:"Hello React"                    }                },                handleClick:function(){                    this.setState({                        value:"Hello World"                    });                },                render:function(){                    var value = this.state.value;                    return (                    <div>                        <Content myData = {value} updataState ={this.handleClick}/>                    </div>                    );                }             });             ReactDOM.render(        <HelloMessage />,        document.getElementById("example")             );    </script></body></html>

React Refs

React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。
这个特殊的属性允许你引用 render() 返回的相应的支撑实例。这样就可以确保在任何时间总是拿到正确的实例。
通过使用 this 来获取当前 React 组件,或使用 ref 来获取组件的引用
当组件插入到 DOM 后,ref 属性添加一个组件的引用于到 this.refs
Demo:

<!DOCTYPE html><html><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <title>React Ref</title></head><body>    <div id="example"></div>    <script type="text/javascript" src="../build/react.js"></script>    <script type="text/javascript" src="../build/react-dom.js"></script>    <script type="text/javascript" src="../build/browser.min.js"></script>    <script type="text/babel">        var MyComponent = React.createClass({            handleClick:function(){                this.refs.myInput.focus();            },            render:function(){                return (                    <div>                        <input type="text" ref = "myInput" />                        <input type="button" value="点我输入框获取焦点" onClick = {this.handleClick}/>                    </div>                );            }        });        ReactDOM.render(            <MyComponent />,            document.getElementById("example")        );    </script></body></html>
1 0
原创粉丝点击