React
React简介FeceBook开源的一套框架,专注于MVC的视图V模块。实质是对V视图的一种实现。 React框架的设计没有过分依赖于某个环境,它自建一套环境,就是virtual DOM(虚拟DOM)。 提供基础API:创建元素,渲染元素。 React的独特之处:
React的核心思想:封装组件,各个组件维护自己的状态和 UI,当状态变更,自动重新渲染整个组件。 浏览器环境中渲染 <script src="lib/react.js" type="text/javascript" charset="utf-8"></script> <script src="lib/react-dom.js" type="text/javascript" charset="utf-8"></script>
JSXJSX是React自定义的语法,最终JSX会转化为JS运行与页面当中 组件组件是React中核心概念,页面当中的所有元素都通过React组件来表达,将要写的React代码绝大部分都是在做React组件的开发。 组合模式: 组合模式又称之为:部分-整体模式。使树形结构的问题中,模式了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂的元素,从而使得客户程序与复杂元素的内部结构解耦。 无论是应用等级还是一个表单亦或是一个按钮,都视为一个组件。然后基于组件的组合构建整个应用。
组合模式优点:
VIRTUAL DOMReact抽象出来的虚拟DOM树,虚拟树是React高性能的关键。(让需要改变的元素才去重新渲染) 单项数据流单项数据流:one-way reactive data flow React应用的核心设计模式,数据流向自顶向下。 页面的UI和数据的对应是唯一的。 基础APIcreateElementReact.createElement(); 创建虚拟DOM 参数1:元素名称, 例如: div,p,h1 let ul = React.createElement('ul',{ 'title': '嘻嘻哈哈' },'这是'); renderReactDOM.render(); 参数1:虚拟DOM元素 ReactDOM.render(ul,document.querySelector('.app')); 示例: <script src="lib/react.js" type="text/javascript" charset="utf-8"></script> <script src="lib/react-dom.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> 'use strict'; let ul = React.createElement('ul',{ 'title': '嘻嘻哈哈' },'这是'); ReactDOM.render(ul,document.querySelector('.app')); </script> crateClassReact.createClass(); 参数:配置对象。 render: 组件中渲染输出的虚拟DOM元素。 // component let Uls = React.createClass({ render: function () { return React.createElement( 'ul',null,React.createElement( 'li','a' ),'b' ),'c' ) ) } }); // 组件变成虚拟DOM let ul = React.createElement(Uls,null); // 渲染页面 ReactDOM.render(ul,document.querySelector('.app')); JSX语法创建JSX语法的本质:使用基于XML的方式表达组件嵌套,保持和HTML一致的结构。最终所有的JSX都会编译为原生JavaScript 嵌套规则:标签可以任意嵌套。标签闭合,必须严格闭合,否则无法编译通过。 编译JSX语法: fis.match('**.jsx',{ parser: fis.plugin('babel2'),rExt: '.js' }); // 渲染HTML内部的JSX语法 fis.match('**.html:jsx',{ parser: fis.plugin('babel2') }); JSX示例: // 创建组件 let Uls = React.createClass({ render: function () { return ( <ul> <li>a</li> <li>b</li> <li>c</li> </ul> ); } }); // 渲染组件成 虚拟DOM let ul = (<Uls></Uls>); // 渲染页面中 ReactDOM.render(ul,document.querySelector('.app')); HTML内部JSX语法<div class="app"></div> <script src="lib/react.js" type="text/javascript" charset="utf-8"></script> <script src="lib/react-dom.js" type="text/javascript" charset="utf-8"></script> <script type="text/x-jsx"> let div = ( <div id="red"> JSX </div> ); ReactDOM.render(div,document.querySelector('.app')); </script> 组件大致分类
虚拟DOM属性为虚拟DOM添加属性,传递属性的方式和HTML相同。 属性可以是字符串,也可以是任意的JavaScrip变量。需要使用插值方式解析变量。 特殊属性: // 创建组件 let Uls = React.createClass({ render: function () { return ( <ul className="listNone"> <li>a</li> <li>b</li> <li>c</li> </ul> ); } }); 对HTML组件 fuunction render () { return <p title={tit}>Hello</p> } React自定义组件 fuunction render () { return <p><CustomComponent></CustomComponent></p> } JSX花括号插值形式,动态的改变虚拟DOM中属性值,或者内容,或使用JavaScript表达式,做简单的运算。 语法: 'use strict'; // Component let Header = React.createClass({ render: function () { let userName = 'cyan'; let date = new Date(); return ( <div className="header"> <div className="inner"> <div className="left"> <span>{userName}</span>   <span>{date.getHours() > 12 ? '下午' : '上午'}</span> </div> </div> </div> ); } }); // 渲染 ReactDOM.render(<Header />,document.querySelector('.app')); JSX注释let Header = React.createClass({ render: function () { {/* 这里是注释 */} } }); Componentprops属性组件中特殊属性:props 设置默认的属性,通过getDefaultProps()来设置,是React内置方法名,在自定义方法的时候,不能重写。
一般的,props规定是只能读取,应该禁止被修改。 属性数据的单项性 React的单项数据流模式,数据的流动管道就是 props,流动的方向就组件的层级自顶向下的方向。所以一个组件是不能修改自身的属性,组件的属性一定是通过父组件传递而来(或默认属性) 'use strict'; // Component let Prat = React.createClass({ getDefaultProps: function () { return { title: ['默认标题'] } },createLi: function () { return this.props.title.map( ( val,idx ) => { return (<li key={idx} >{ val }</li>); } ); },render: function () { // console.log( this.props.children ); // console.log( this.props ); return ( <div className="part"> <ul className="header"> {this.createLi()} </ul> </div> ); } }); // 渲染 ReactDOM.render(<Prat />,document.querySelector('.app')); ReactDOM.render(<Prat title={['新闻','今日话题']} />,document.querySelector('.app1')); style设置style的样式
注意:样式并不能像HTML行内一样,需要使用插值方式,插值中使用对象。 'use strict'; // Componedt let Style = React.createClass({ render: function () { let sty = { color: 'red',border: '1px solid #000',borderBottom: '2px solid tan' } return ( <h1 style={sty}> title <h1 style={{'background': 'tan' }}>titile2</h1> </h1> ); } }); // 渲染 ReactDOM.render(<Style />,document.querySelector('.app')); EventReact中为虚拟DOM添加事件与HTML为DOM添加事件一样: <div onClick="fn"></div> 一般的为React添加的DOM事件,并不要字符串,需要使用插值符号为虚拟DOM添加事件回调函数。 // Componedt let Style = React.createClass({ changeContent: function ( ev ) { ev.target.innerHTML = '修改后的文案'; },render: function () { let sty = { color: 'red',borderBottom: '2px solid tan' } return ( <div style={sty}> title <h1 style={{'background': 'tan' }} onClick={this.changeContent}>titile2</h1> </div> ); } }); // 渲染 ReactDOM.render(<Style />,document.querySelector('.app')); state状态无状态组件属性 对于无状态组件,可以添加 .propTypes 和 .defaultProps 属性到函数上。 如果一个在渲染页面之后组件不会变化,可以通过props就可以实现对组件的样式设置以及行为渲染,此时组件不会收到外界的影响,组件是一成不变的,这类组件叫做: 无状态satateless组件. state 对于大部分的组件来说,通常是要通与外界交流,此时组件要处于不同的状态,此时的组件就要有状态,对于组件内部的状态控制,可以通过state属性控制. state属性: 控制组件的内部状态. getInitialState() : 初始化状态, setState() : 设置状态 state每次更新都会触发一次render() 方法. // 创建 Component let Dom = React.createClass({ getInitialState: function () { return { index: 0,txt: '嘻嘻哈哈' } },render: function () { // console.log( this.state ); return ( <div> <button onClick={this.clickContent}>点击显示内容</button> <p>{this.state.txt}</p> </div> ); },clickContent: function () { this.setState({ txt: '么么哒' }); } }); // 渲染组件 ReactDOM.render(<Dom />,document.querySelector('.app')); Component生命周期
生命周期的方法都是在调用 React.createClass(); 的参数配置对象传入.
mixins mixins: React的插件列表。通过这种模式在不同组件之间共享方法数据或者行为只需共享mixin即可。 statics statics : 定义组件的类方法。 // Component let oDiv = React.createClass({ // 定义组件类方法 statics: { statisMethod: () => { return true; } },// Class 分为类方法和实例方法, 实例方法可以访问this,而类方法不能。 // 不能在Class中返回状态或者属性。 render: function () { return ( <div>嘻嘻哈哈</div> ); } }); // 渲染组件 ReactDOM.render(<oDiv />,document.querySelector('.app')); displayName displayName : 组件的名称,JSX在转为JavaScript的时候自动设置displayName。 也可以手动设置。
整个组件的生命周期,包含:
组件实例化
componentWillMount() componentDidMount(); // Component let GoBack = React.createClass({ getDefaultProps: function () { console.log(111); return { title: '' } },getInitialState: function () { console.log(222); return { sateteTitle: this.props.title } },componentWillMount: function () { console.log(333,this.satate,this.props); },render: function () { console.log(444); return (<div className="go-back">返回顶部</div>); },componentDidMount: function () { console.log(555); const _this = this; setTimeout(() => { _this.setState({ stateTitle: '修改后title' }); },1000); } }); // 渲染 ReactDOM.render(<GoBack />,document.querySelector('.app') ); 在未初始化props之前,无法使用 组件存在期 一旦组件被创建,那么就进入了组件的存在期,在存在期中,每次组件更新的时候,会进入新的5个阶段.
componentWillReceivePros(newProps); 获取新的属性,但并不能确定属性一定改变了,例如: 一个组件被多次渲染到DOM中. shouldComponentUpdate() 条件:接收到新属性或新状态的时候在render前 会被调用(除了调用forceUpdate 和 初始化渲染以外) componentWillUpdate() 条件: 当组件确定要更新,在render()之前被调用. componentDidUpdate() 条件:更新被应用到DOM之后 存在期中的方法,在组件第一次渲染的时候,不会执行,componentWillReceiveProps();方法在组件内部状态更新的是不会被调用. 销毁期 组件生命周期的最后个阶段,到了这个阶段,也就是说,组件要被销毁了。 componentWillUnmount()
React的核心模式是单项数据流。在组件内部的生命周期中也是符合单项数据的模式。数据从组件的属性流入,再结合组件的状态,流入生命周期的方法,直到渲染结束,都应该是一个单向的过程,其间不能随意改变组件的状态。 子组件子组件: 在组件内部使用其它组件的时候,组件被嵌套该组件中,作为子组件使用. 作为一个父组件的子组件,可以通过属性传递数据信息,直接在父组件中,对子组件添加属性. 注意:渲染组件的时候,只需要渲染父组件即可. 父组件传递数据信息给子组件方法: 1: 通过属性传递数据信息,直接在父组件中对子组件添加属性信息。 let Main = React.createCalss({ render: function () { return ( <div className="main"> {/* 子组件 */} <GoBack title="返回组件title"/> </div> ); } }); // 缺点: 父组件向子组件中传递数据的时候,是固定的,当父组件更新的时候,没拌饭更新子组件的属性. 2: 通过父组件的属性 let Main = React.createClass({ getDefaultProps: function () { return { title: '' } },render: function () { return ( <div className="main"> {/* 子组件 */} <GoBack title={this.props.title} /> </div> ); } }); 3: 通过父组件的状态 let Main = React.createClass({ getDefaultProps: function () { return { title: '' } },getInitialState: function () { return { title: '么么哒' } },render: function () { return ( <div className="main"> {/* 子组件 */} <GoBack title={this.state.title} /> </div> ); } }); 组件的作用域,与JavaScript变量的作用域机制一样. 子组件会寻找自身的prop属性,state状态。然后寻找父组件的prop属性,state状态。 兄弟组件的信息传递每个组件都有自己的完整空间,彼此之间没有联系,如何实现兄弟组件之间的通信。 父组件和子组件通信,可以通过设置子组件的属性: 传递固定值,属性值,状态值,还可以传递方法或者函数。 注意: 传递方法或者函数时:事件对象是组建绑定的元素。this指向父组件。 子组件向父组件传递消息,可以通过父组件为子组件添加函数,子组件通过调用该函数,传递参数数据来实现。 // InputMsg Component const InputMsg = React.createClass({ render: function () { // console.log( this.props.changeMsg() ); return ( <div> <input type="text" onChange={this.props.changeMsg} /> </div> ); } }); // App Component const App = React.createClass({ getInitialState: function () { return { msg: 'world' } },render: function () { return ( <div className="mian"> {/* 父组件传递方法 */} <InputMsg changeMsg={this.changeMsg} /> </div> ); },changeMsg: function ( ev ) { // let vals = ev.target.value; console.log( vals ); // console.log( ev ); // console.log( this ); } }); // render ReactDOM.render(<App />,document.querySelector('.app')); 兄弟组件之间的通讯,需要通过它们共同的父组件的state或者props来实现。 'use strict'; // 实现 组件之间的 双向数据绑定 // InputMsg Component const InputMsg = React.createClass({ render: function () { // console.log( this.props.changeMsg() ); return ( <div> <input type="text" onChange={this.props.changeMsg} /> </div> ); } }); // ShowMsg Component const ShowMsg = React.createClass({ getDefaultProps: function () { return { msg: '嘻嘻哈哈' } },render: function () { return ( <div> <p>{ this.props.msg }</p> </div> ); } }); // App Component const App = React.createClass({ getInitialState: function () { return { msg: 'world' } },render: function () { return ( <div className="mian"> <InputMsg changeMsg={this.changeMsg} /> <ShowMsg msg={this.state.msg} /> </div> ); },changeMsg: function ( ev ) { let vals = ev.target.value; this.setState({ msg: vals }); } }); // render ReactDOM.render(<App />,document.querySelector('.app')); 4,子组件传递信息给父组件 子组件向父组件传递消息,可以通过父组件为子组件添加函数实现,子组件通过调用该方法,并通过处理之后的数据用参数形式传递给父组件来完成。 父组件定义方法,子组件调用方法 事件处理与合成事件React只需把事件处理器,以驼峰命名形式当作组件props传入。就像是用普通HTML事件一样。 需要在手机或平板等触摸设备上使用React,在React版本 findAllInRenderedTree 自动绑定和事件代理AutoBinding: 在JavaScript里创建回调函数的时候,保证this的正确性,一般都需要显示的绑定方法到它的实力上, React所有方法被自动绑定到它的组件实例上。 事件代理: React并没有把时间处理器绑定到节点本省。当React启动的时候,它在最外层使用一个唯一的事件监听器处理所有时间。当组件被加载和销毁时,只是在内部映射里添加或删除事件处理器。当事件触发,React根据映射来决定如何分发。当映射里处理器时,会当作空操作处理。 组件其实是状态机React 把用户界面当作简单状态机。把用户界面想象成拥有不同状态然后渲染这些状态,可以轻松让用户界面与数据保持一致。 React中,只需要更新组件的state,然后根据新的state重新渲染用户界面(不要操作DOM)。React来决定如何最高效的更新DOM。 state工作原理常用的通知React数据变化的方法时调用 setState(data,callback); 这个方法会合并(merge) data 到 this.state ,并重新渲染组件。渲染完成后,调用可选的callback回调。大部分情况下不需要提供callback,因为React会负责把界面更新到最新的状态。 哪些组件应该有State 大部分组件的工作应该是冲 props 里面 取出数据并渲染。但是,有时候需要和用户俗话如,服务器请求数据,或者时间变化等做出相应,这时才需使用State。 尝试把尽可能多的组件无状态化这样做能隔离state , 作用: 把它放到最合理的地方,也能减少冗余,同时易于解释程序运作过程。 常用的模式是:创建多个只负责渲染数据的无状态组件,在它们的上层创建一个有状态的组件并把它的状态通过props传给子级。这个有状态的组件封装了所有用户的交互逻辑,而这些无状态组件负责声明式的渲染数据。 哪些应该作为State state应该包括那些可能被组件的事件处理器改变并触发用户界面更新的数据。真实的应用中这种数据一般都很小且能被JSON序列化。当创建一个状态化的组件时,想象一下表示它的状态最少需要哪些数据,并只会把这些数据存入 this.state。在render() 里再根据state来计算需要的其它数据。
哪些不应该作为 State this.state 应该仅包括能够表示用户界面状态所需的最少数据。 不应该包括state:
React与DOM获取DOM元素第一种方式: 获取使用: 第二种方式: 一般在组件实例化完成阶段使用 注意:不能使用在无状态组件上. const Checkbox = React.createClass({ getInitialState: function () { return { cb1: false,cb2: false } },render: function () { return ( <div> <button onClick={this.showReslut}>结果</button> <input ref="cb1" type="checkbox" defaultChecked="true" onChange={this.change} />篮球 <input ref="cb2" type="checkbox" />足球 </div> ); },componentDidMount: function () { let dom = ReactDOM.findDOMNode(this); let inps = ReactDOM.findDOMNode( this.refs.cb1 ); // 获取 this.refs.cb1 的 所在DOM,并不能传入 this.refs。 },showReslut: function () { console.log( this.refs.cb1.checked,this.refs.cb2.checked ); },change: function ( ev ) { let cheVals = ev.target.checked; this.setState({ 'cb1': cheVals }); } }); // render ReactDOM.render(<Checkbox />,document.querySelector('.app')); 非元素属性非元素属性: 不是DOM元素原生就有的属性。(例如:自定义属性,React提供的特殊属性,ref等) 'use strict'; let Search = React.createClass({ render: function () { // 模拟搜索之后文案显示 let content = { __html: '<span style="color: cyan">搜索结果,么么哒</span>' } return ( <div className="search-grpup"> <input ref="serachInput" type="text" /> <button onClick={this.clickSearch}>搜索</button> <span dangerouslySetInnerHTML={content}></span> {/* 使用行内式的样式,需要通过 dangerouslySetInnerHTML属性设置 */} </div> ); },clickSearch: function ( ev ) { let vals = this.refs.serachInput.value; console.log(vals); } }); // 渲染 ReactDOM.render(<Search />,document.querySelector('.app')); key: 列表中元素的ID。通过设置key是的每个列表元素获取ID 定义: let content = { __html: '<span style="color: cyan">搜索结果,么么哒</span>' } 使用: <span dangerouslySetInnerHTML={content}></span> 约束性组件和非约束性组件约束性组件:状态是交由组件自身管理(state是通过初始化,自定义方法设置状态) 一般的,约束性组件与非约束性组件是对表单元素而言的。 非约束性组件 非约束性组件,表单值与是由用户输入。 'use strict'; // Component const Search = React.createClass({ clickBtn: function ( ev ) { let vals = this.refs.serchInput.value; console.log(vals); },render: function () { return ( <div className="serach"> <div className="serach-logo"> {/* <input ref="serchInput" type="text" placeholder="用户输入的内容" /> */} <input ref="serchInput" type="text" defaultValue="用户输入的内容" /> <button onClick={this.clickBtn}>搜索</button> </div> </div> ); } }); // render ReactDOM.render(<Search />,document.querySelector('.app')); placeholder与defaultValue的区别: 获取表单内的内容需要设置ref="names",获取需要:this.refs.names。 约束性组件 表单元素的value值交给组件的state管理,称之为: 约束性组件。 优点:元素的值交由组件管理,表单验证更加灵活。 'use strict'; const Search = React.createClass({ getInitialState: function () { return { inp: '默认状态',txt: '' } },render: function () { return ( <div className="search"> <div className="search-group"> <input type="text" placeholder={this.state.inp} onChange={this.inpChange} /> <button>百度一下</button> <span>{this.state.txt}</span> </div> </div> ); },inpChange: function ( ev ) { let vals = ev.target.value; if ( vals.length > 10 ) { this.setState({ inp: vals,txt: '不能超过10个字符' }); } } }); // 渲染 ReactDOM.render(<Search />,document.querySelector('.app')); 几种约束性组件 select 'use strict'; const Select = React.createClass({ // 初始化 状态 getInitialState: function () { return { selectValue: '' } },render: function () { return ( <div> <select defaultValue={this.state.selectValue} onChange={this.changeSelect}> <option value="cyan">cyan</option> <option value="tan">tan</option> <option value="khaki">khaki</option> </select> <span></span> </div> ); },changeSelect: function ( ev ) { let vals = ev.target.value; this.setState({ selectValue: vals }); } }); // render ReactDOM.render(<Select />,document.querySelector('.app')); 如果使用ref来获取表单元素中的内容,使用default加前缀,例如: defaultValue,defaultChecked. 。通过refs来获取值 'use strict'; const Checkbox = React.createClass({ getInitialState: function () { return { cb1: false,document.querySelector('.app')); 与其它库一起使用侵入式插件 并不一定是使用React的组件的生命周期事件 需要在 也可以这种方式来绑定事件监听,甚至事件流 混合React支持混合, 将混合中的方法赋值到组件对象上。组件对象可以使用混合中定义的方法。 一般是自定义方法,放置mixin中。 使用混合,值是一个数组,复制多个对象上面的属性和方法。混合可以看做是一种多继承。 定义: let MixinMethod = {} 使用: mixins: [MixinMethod] Airbnb React基本规则
React组件的内部方法命名不要使用下划线前缀。 命名扩展名: React组件使用 import reservationCard from './ReservationCard'; const ReservationItem = <ReservationCard /> 组件命名: 组件名称应该和文件名一致。 例如:Reservation.jsx 中 有一个Reservation 的引用名称。但是,如果是在目录中的组件,应该使用 index.jex作为文件名并且使用文件夹名称作为组件名. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |