是什么html
为何react
怎么用ajax
搭建示例应用json
生态圈/公用组件api
应用框架数组
编译/合并代码服务器
react 是一个作 UI 的库,具体来讲是作 UI 组件的库,专一于作 mvc 中的 v.mvc
<div id="container"> </div> <script> React.createClass({ render: function() { return <div>Hello {this.props.name}</div>; } }); React.render(<Hello name="World" />, document.getElementById('container')); </script>
能够把一个组件看作一个状态机, 每一次状态对应于组件的一个 ui框架
var Timer = React.createClass({ getInitialState: function() { return {secondsElapsed: 0}; }, tick: function() { this.setState({secondsElapsed: this.state.secondsElapsed + 1}); }, componentDidMount: function() {//插入真实DOM以后被执行 this.interval = setInterval(this.tick, 1000); }, componentWillUnmount: function() { //移除DOM以前被执行 clearInterval(this.interval); }, render: function() { return ( <div>Seconds Elapsed: {this.state.secondsElapsed}</div> ); } }); React.render(<Timer />, document.getElementById('container'));
api 少,类库易学dom
组件内聚,易于组合
原生组件和自定义组件融合渲染
状态/属性驱动全局更新,不用关注细节更新
commonjs 生态圈/工具链完善
jsx
event
composition
props/state
mixin
form
refs
component api
top api
相似 xml 的语法,用来描述组件树
<div classname="x"> <a href="#">#</a> <component x="y">1</component> </div> React.createElement('div',{ className:'x' },[ React.createElement('a',{href:'#'},'#'), React.createElement(Component,{x:'y'},1); ]);
注意和 html 语法不太同样,好比必须是驼峰命名, 以及属性名不能和 js 关键字冲突,例如:className,readOnly
能够经过 {变量名} 来将变量的值做为属性值
var x = 'http://www.baidu.com'; var y = <a href= {x} target="_blank">baidu.com</a>; React.render(y, document.getElementById('container'));
能够用经过 {...obj} 来批量设置一个对象的键值对到组件的属性,注意顺序
var x = 'http://www.baidu.com'; var obj = { href:"http://www.taobao.com", target:"_blank" } var y = <a {...obj} href= {x}>baidu.com</a>; React.render(y, document.getElementById('container'));
经过 this.props 能够获取传递给该组件的属性值,还能够经过定义 getDefaultProps 来指定默认属性值
var B = React.createClass({ getDefaultProps(){ return { title:'default' }; }, render(){ return <b>{this.props.title}</b> } }); React.render(<div> <B title="指定 "/> <B/> </div>,document.getElementById('container'));
经过指定 propTypes 能够校验属性值的类型
var B = React.createClass({ propTypes: { title: React.PropTypes.string, }, getDefaultProps(){ return { title:'default' }; }, render(){ return <b>{this.props.title}</b> } }); React.render(<div> <B title="指定 "/> <B title={2}/> </div>,document.getElementById('container'));
注意:校验仅为提高开发者体验
组件内部的状态,能够使用 state
var Timer = React.createClass({ getInitialState: function() { return {secondsElapsed: 0}; }, tick: function() { this.setState({secondsElapsed: this.state.secondsElapsed + 1}); }, componentDidMount: function() { this.interval = setInterval(this.tick, 1000); }, componentWillUnmount: function() { clearInterval(this.interval); }, render: function() { return ( <div>Seconds Elapsed: {this.state.secondsElapsed}</div> ); } }); React.render(<Timer />, document.getElementById('container'));
能够经过设置原生 dom 组件的 onEventType 属性来监听 dom 事件,例如 onClick, onMouseDown,在增强组件内聚性的同时,避免了传统 html 的全局变量污染
var LikeButton = React.createClass({ getInitialState: function() { return {liked: false}; }, handleClick: function(event) { this.setState({liked: !this.state.liked}); }, render: function() { var text = this.state.liked ? 'like' : 'haven\'t liked'; return ( <p onClick={this.handleClick}> You {text} this. Click to toggle. </p> ); } }); React.render( <LikeButton />, document.getElementById('container'));
注意:事件回调函数参数为标准化的事件对象,能够不用考虑 ie
能够像使用原生 dom 组件同样使用自定义的组件
var A = React.createClass({ render(){ return <a href='#'>a</a> } }); var B = React.createClass({ render(){ return <i><A /> !</i>; } }); React.render(<B />,document.getElementById('container'));
自定义组件中能够经过 this.props.children 访问自定义组件的子节点
var B = React.createClass({ render(){ return <ul> {React.Children.map(this.props.children,function(c){ return <li>{c}</li>; })} </ul>; } }); React.render(<B> <a href="#">1</a> 2 </B>,document.getElementById('container'));
mixin 是一个普通对象,经过 mixin 能够在不一样组件间共享代码
var mixin = { propTypes: { title: React.PropTypes.string, }, getDefaultProps(){ return { title:'default' }; }, }; var A = React.createClass({ mixins: [mixin], render(){ return <i>{this.props.title}</i> } }); var B = React.createClass({ mixins: [mixin], render(){ return <b>{this.props.title}</b> } }); React.render(<div> <B/> <A title={2}/> <A/> </div>,document.getElementById('container'));
和 html 的不一样点:
value/checked 属性设置后,用户输入无效
textarea 的值要设置在 value 属性
select 的 value 属性能够是数组,不建议使用 option 的 selected 属性
input/textarea 的 onChange 用户每次输入都会触发(即便不失去焦点)
radio/checkbox 点击后触发 onChange
若是设置了 value 属性,那么改组件变为受控组件,用户没法输入,除非程序改变 value 属性
var Test = React.createClass({ render(){ return <input value="x" /> } }); React.render(<Test />,document.getElementById('container'));
能够经过监听 onChange 事件结合 state 来改变 input 的值
var Test = React.createClass({ getInitialState(){ return { value:'xasdasdf' }; }, onChange(e){ this.setState({ value:e.target.value }); }, render(){ return <input value={this.state.value} onChange={this.onChange}/> } }); React.render(<Test />,document.getElementById('container'));
设置 defaultValue 为设置 input 的初始值,以后 input 的值由用户输入
var Test = React.createClass({ render(){ return <input defaultValue="xyz" /> } }); React.render(<Test />,document.getElementById('container'));
该功能是为告终合现有非 react 类库,经过 ref/refs 能够取得组件实例,进而取得原生节点
var Test = React.createClass({ componentDidMount(){ alert(React.findDOMNode(this.refs.content).innerHTML); }, render(){ return <div> <h3>header</h3> <div ref='content'>content</div> </div>; } }); React.render(<Test />,document.getElementById('container'));
React.createClass 定义组件时容许传入的配置
getDefaultProps 获得默认属性对象
propTypes 属性检验规则
mixins 组件间公用方法
React.createClass 定义时容许传入的函数,会在特定生命周期内调用
getInitialState 获得初始状态对象
render 返回组件树. 必须设置
componentDidMount 渲染到 dom 树中是调用,只在客户端调用,可用于获取原生节点
组件的属性值改变时调用
componentWillReceiveProps 属性改变调用
shouldComponentUpdate 判断是否须要从新渲染
render 返回组件树. 必须设置
componentDidUpdate 渲染到 dom 树中是调用, 可用于获取原生节点
最后是 componentWillUnmount 组件从 dom 销毁前调用
function log(str){ document.getElementById('log').innerHTML+='<p>'+str+'</p>';; } document.getElementById('clear').onclick=function(){ document.getElementById('log').innerHTML=''; }; var Test = React.createClass({ getInitialState() { log('getInitialState'); return { value: this.props.value }; }, componentWillReceiveProps(nextProps){ log('componentWillReceiveProps'); this.setState({ value: nextProps.value }); }, shouldComponentUpdate(nextProps,nextState){ log('shouldComponentUpdate'); return true; }, componentWillUpdate(nextProps,nextState){ log('componentWillUpdate'); }, componentWillMount(){ log('componentWillMount'); }, render() { log('render'); return <span>{this.props.value}</span> }, componentDidMount() { log('componentDidMount'); }, componentDidUpdate(prevProps,prevState) { log('componentDidUpdate'); }, componentWillUnmount(prevProps,prevState) { log('componentWillUnmount'); } }); var Hello = React.createClass({ getInitialState() { return { value:1, destroyed:false }; }, increase() { this.setState({ value: this.state.value+1 }); }, destroy() { this.setState({ destroyed: true }); }, render: function() { if(this.state.destroyed){ return null; } return <div> <p> <button onClick={this.increase}>increase</button> <button onClick={this.destroy}>destroy</button> </p> <Test value={this.state.value}/> </div>; } }); React.render(<Hello />, document.getElementById('container'));
React.createClass 建立组件类
React.findDOMNode 从组件实例获取 dom 根节点
React.render 渲染组件到 dom
React.Children.* 操做 map/forEach children 工具类
var Comment = React.createClass({ render: function () { var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> <span dangerouslySetInnerHTML={{__html: rawMarkup}} /> </div> ); } }); var CommentList = React.createClass({ render: function () { var commentNodes = this.props.data.map(function (comment) { return ( <Comment author={comment.author}> {comment.text} </Comment> ); }); return ( <div className="commentList"> {commentNodes} </div> ); } }); var CommentForm = React.createClass({ getInitialState() { return { name: '', text: '' } }, updateField(field, e) { var state = {}; state[field] = e.target.value; this.setState(state); }, handleSubmit(e){ e.preventDefault(); this.props.onPost({ author:this.state.name, text:this.state.text }); this.setState({ name:'', text:'' }); }, render: function () { return ( <form className="commentForm" onSubmit={this.handleSubmit}> <input placeholder="Your name" value={this.state.name} onChange={this.updateField.bind(this, 'name')}/> <input placeholder="Say something..." value={this.state.text} onChange={this.updateField.bind(this, 'text')} /> <input type="submit" value="Post" /> </form> ); } }); var database=[ { author: '做者 1', text: '评论 1,' + Date.now() }, { author: '做者 2', text: ' *评论 2,' + Date.now() + '* ' } ]; var CommentBox = React.createClass({ loadCommentsFromServer: function () { var self = this; $.ajax({ url: this.props.url, method:'post', dataType:'json', data: { json:JSON.stringify({ data:database }) }, success(res) { self.setState({data: res.data}) } }); }, getInitialState: function () { return {data: []}; }, handlePost(post){ database.push(post); this.loadCommentsFromServer(); }, componentDidMount: function () { this.loadCommentsFromServer(); }, render: function () { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onPost={this.handlePost}/> </div> ); } }); React.render( <CommentBox url="/echo/json/" />, document.getElementById('container') );
顶层 CommentBox
评论列表 CommentList
单条评论 Comment
评论表单 CommentForm
var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> Hello, world! I am a CommentBox. </div> ); } }); React.render( <CommentBox />, document.getElementById('container') );
var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> Hello, world! I am a CommentList. </div> ); } }); var CommentForm = React.createClass({ render: function() { return ( <div className="commentForm"> Hello, world! I am a CommentForm. </div> ); } }); var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList /> <CommentForm /> </div> ); } }); React.render( <CommentBox />, document.getElementById('container') );
var Comment = React.createClass({ render: function() { return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> {this.props.children} </div> ); } }); var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> <Comment author="做者 1">评论 1</Comment> <Comment author="做者 2">评论 2</Comment> </div> ); } }); var CommentForm = React.createClass({ render: function() { return ( <div className="commentForm"> Hello, world! I am a CommentForm. </div> ); } }); var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList /> <CommentForm /> </div> ); } }); React.render( <CommentBox />, document.getElementById('container') );
var Comment = React.createClass({ render: function() { var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> <span dangerouslySetInnerHTML={{__html: rawMarkup}} /> </div> ); } }); var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> <Comment author="做者 1">评论 1</Comment> <Comment author="做者 2"> *评论 2* </Comment> </div> ); } }); var CommentForm = React.createClass({ render: function() { return ( <div className="commentForm"> Hello, world! I am a CommentForm. </div> ); } }); var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList /> <CommentForm /> </div> ); } }); React.render( <CommentBox />, document.getElementById('container') );
var data = [ {author: "做者 1", text: "评论 1"}, {author: "做者 2", text: "*评论 2*"} ]; var Comment = React.createClass({ render: function() { var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> <span dangerouslySetInnerHTML={{__html: rawMarkup}} /> </div> ); } }); var CommentList = React.createClass({ render: function() { var commentNodes = this.props.data.map(function (comment) { return ( <Comment author={comment.author}> {comment.text} </Comment> ); }); return ( <div className="commentList"> {commentNodes} </div> ); } }); var CommentForm = React.createClass({ render: function() { return ( <div className="commentForm"> Hello, world! I am a CommentForm. </div> ); } }); var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={data}/> <CommentForm /> </div> ); } }); React.render( <CommentBox />, document.getElementById('container') );
var Comment = React.createClass({ render: function () { var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> <span dangerouslySetInnerHTML={{__html: rawMarkup}} /> </div> ); } }); var CommentList = React.createClass({ render: function () { var commentNodes = this.props.data.map(function (comment) { return ( <Comment author={comment.author}> {comment.text} </Comment> ); }); return ( <div className="commentList"> {commentNodes} </div> ); } }); var CommentForm = React.createClass({ render: function () { return ( <div className="commentForm"> Hello, world! I am a CommentForm. </div> ); } }); var CommentBox = React.createClass({ loadCommentsFromServer: function () { var self = this; new Request.JSON({ url: this.props.url, data: { json: JSON.encode({ data: [ { author: '做者 1', text: '评论 1,' +Date.now() }, { author: '做者 2', text: ' *评论 2,'+Date.now()+'* ' } ] }), delay:1 }, onSuccess(res) { self.setState({data: res.data}) } }).send(); }, getInitialState: function () { return {data: []}; }, componentDidMount: function () { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function () { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } }); React.render( <CommentBox url="/echo/json/" pollInterval={2000} />, document.getElementById('container') );
var Comment = React.createClass({ render: function () { var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> <span dangerouslySetInnerHTML={{__html: rawMarkup}} /> </div> ); } }); var CommentList = React.createClass({ render: function () { var commentNodes = this.props.data.map(function (comment) { return ( <Comment author={comment.author}> {comment.text} </Comment> ); }); return ( <div className="commentList"> {commentNodes} </div> ); } }); var CommentForm = React.createClass({ getInitialState() { return { name: '', text: '' } }, updateField(field, e) { console.log(e); var state = {}; state[field] = e.target.value; this.setState(state); }, handleSubmit(e){ e.preventDefault(); this.props.onPost({ name:this.state.name, text:this.state.text }); this.setState({ name:'', text:'' }); }, render: function () { return ( <form className="commentForm" onSubmit={this.handleSubmit}> <input placeholder="Your name" value={this.state.name} onChange={this.updateField.bind(this, 'name')}/> <input placeholder="Say something..." value={this.state.text} onChange={this.updateField.bind(this, 'text')} /> <input type="submit" value="Post" /> </form> ); } }); var database=[ { author: '做者 1', text: '评论 1,' + Date.now() }, { author: '做者 2', text: ' *评论 2,' + Date.now() + '* ' } ]; var CommentBox = React.createClass({ loadCommentsFromServer: function () { var self = this; $.ajax({ url: this.props.url, method:'post', dataType:'json', data: { json:JSON.stringify({ data:database }) }, success(res) { console.log(res) self.setState({data: res.data}) } }); }, getInitialState: function () { return {data: []}; }, handlePost(){ }, componentDidMount: function () { this.loadCommentsFromServer(); }, render: function () { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onPost={this.handlePost}/> </div> ); } }); React.render( <CommentBox url="/echo/json/" />, document.getElementById('container') );
var Comment = React.createClass({ render: function () { var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> <span dangerouslySetInnerHTML={{__html: rawMarkup}} /> </div> ); } }); var CommentList = React.createClass({ render: function () { var commentNodes = this.props.data.map(function (comment) { return ( <Comment author={comment.author}> {comment.text} </Comment> ); }); return ( <div className="commentList"> {commentNodes} </div> ); } }); var CommentForm = React.createClass({ getInitialState() { return { name: '', text: '' } }, updateField(field, e) { var state = {}; state[field] = e.target.value; this.setState(state); }, handleSubmit(e){ e.preventDefault(); this.props.onPost({ author:this.state.name, text:this.state.text }); this.setState({ name:'', text:'' }); }, render: function () { return ( <form className="commentForm" onSubmit={this.handleSubmit}> <input placeholder="Your name" value={this.state.name} onChange={this.updateField.bind(this, 'name')}/> <input placeholder="Say something..." value={this.state.text} onChange={this.updateField.bind(this, 'text')} /> <input type="submit" value="Post" /> </form> ); } }); var database=[ { author: '做者 1', text: '评论 1,' + Date.now() }, { author: '做者 2', text: ' *评论 2,' + Date.now() + '* ' } ]; var CommentBox = React.createClass({ loadCommentsFromServer: function () { var self = this; $.ajax({ url: this.props.url, method:'post', dataType:'json', data: { json:JSON.stringify({ data:database }) }, success(res) { self.setState({data: res.data}) } }); }, getInitialState: function () { return {data: []}; }, handlePost(post){ database.push(post); this.loadCommentsFromServer(); }, componentDidMount: function () { this.loadCommentsFromServer(); }, render: function () { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onPost={this.handlePost}/> </div> ); } }); React.render( <CommentBox url="/echo/json/" />, document.getElementById('container') );
新生成组件/更新组件
checked/unchecked 交互处理
键盘
label?
var Checkbox = React.createClass({ getDefaultProps() { return { defaultChecked: false, onChange(){} }; }, getInitialState() { var state = {}; var props = this.props; if('checked' in props){ state.checked = props.checked; } else { state.checked = props.defaultChecked; } return state; }, componentWillReceiveProps(newProps){ // 组件从新渲染了,属性可能有改变,同步属性到状态 if('checked' in newProps){ this.setState({ checked: newProps.checked }); } }, onClick() { var nextChecked = !this.state.checked; if(!('checked' in this.props)){ // 非受限 this.setState({ checked: nextChecked }); } // 回调函数通知外部 this.props.onChange(nextChecked); }, render() { var state = this.state; var style = {border:'1px solid red',display:'inline-block',width:100,height:100} if(state.checked){ style.backgroundColor='red'; } return <span style={style} onClick={this.onClick}></span>; } }); var Test = React.createClass({ getInitialState(){ return { checked: false }; }, onChange(){ this.setState({ checked: !this.state.checked }); }, render(){ return <div> <p>受限: <Checkbox checked={this.state.checked} /></p> <p>不受限: <Checkbox defaultChecked={true} onChange={this.onChange}/></p> </div>; } }); React.render(<Test />, document.getElementById('container'));
说明:from yiminghe