PS:开头的一段废话css
想起一个月前还不知道reactjs该如何下手的而今天有点小体会,仍是有点小欣慰,不过回望一些走过的坑和开始时的满头浆糊以为仍是有点恐怖的。今天分享一点实践中的当心得给新手朋友们。node
其余的就没必要多说,只说说两个点:react
constructor和superjquery
this.functionName=this.functionName.bind(this)webpack
constructor(props)和super(props)通常是要么不出现,要么同时出现,意义实际上就是继承,这两个东西其实并非reactjs的,而是es6的,前者就是一个通常意义的构造函数,至关于es5里面的git
function FunctionName(props) { this.props=props; }
super(props)则是继承父类的属性,(意义至关于es5中的 function Son(name){ Parent.call(this, name) }),并在constructor内部正确拿到this,这个this指向此时的子类。若是在操做this以前(好比console.log(this))没有写super(props)则会报错,意思大概是:不能在super()以前写this!es6
而有时候看到constructor()和super(),即没有写props好像也没有什么问题,缘由天然是没有在constructor内部用到this.props,实际上在constructor内部通常用到的是this.state居多,貌似this.props没怎么写。。。github
this.functionName=this.functionName.bind(this)这个是绑定方法到子类上,使得这个this就是当前的子类(所谓的this指向)。还能够直接将.bind(this)写函数定义的地方,好比在render渲染的元素上 onClick={this.handleClick.bind(this)}.web
state在reactjs组件状态渲染里面的做用不言而喻,被称为状态渲染机,元素节点的各类属性值及其改变实际上基本是由state提供的状态值及其改变完成的。好比元素的文本改变、表单的value值、checked、disabled甚至css样式均可以作到用state来渲染。如下提供一个简例辅助说明:ajax
import React from 'react'; import ReactDOM from 'react-dom'; import $ from 'jquery'; class Comp extends React.Component { constructor(){ super(); this.handleChange=this.handleChange.bind(this); this.handleClick=this.handleClick.bind(this); this.state={ value: "", msg: "" } } handleChange(e){ this.setState({ value: e.target.value }) } handleClick(){ let {value}=this.state; $.ajax({ ... data: { value:value }, success:(data)=>{ this.setState({ msg: data }) } }) } render(){ let {value,msg}=this.state; return( <div> <input type="text" value={value} onChange={this.handleChange} /> <input type="button" value="提交" onClick={this.handleClick} /> <span>{msg? msg:"此处加载ajax返回的信息"}</span> </div> ) } } ReactDOM.render( <Comp />, document.body)
以上简例在页面上渲染以后是一个按钮、一个输入框和一个信息提示。因为reactjs提倡单向数据流,在value状态初始为空的状况下,若是直接在输入框中输入而不设置value状态(setState),输入信息没法获取。这个渲染过程是:首先页面加载时根据默认的this.state中的三个状态值生成相应的状态,onChange事件不断改变state的value值,此时state接收到了改变并立刻从新渲染页面上输入框内的值,即:只要任何动做改变了state值,页面就会从新渲染相应的地方(关于其余reactjs入门案例demo能够参见本人的github)。
注意一下,以上说constructor内若是没有传递props参数,其内部就不能使用this.props。但这并不意味着其余地方好比render内部不能使用。目前只是体会到组件之间传递的props值的初始来源通常都是state值,多是实践不够的缘由 @_@。。。
这是比较常见的父子组件之间通讯的方式。子组件上的属性值能够理解为一个参数,而须要父组件传递一个实际值。传值这种方式通常是复用组件所必需的,由于有可能有多个页面的内容的某一个部分高度类似甚至相同,这时只须要对一个组件传递不一样的值就能够实现屡次利用。以下例:
//子组件Son.js class Son extends React.Component{ render(){ let {title,userValue,pwdValue,handleChange,handleSubmit}=this.props; return( <div> <h3>{title}</h3> <input type="text" value={userValue} onChange={(e)=>handleChange("user",e.target.value} /> <input type="password" value={pwdValue} onChange={(e)=>handleChange("pwd",e.target.value} /> <input type="button" value="提交" onClick={handleSubmit} /> </div> ) } }
//父组件1:Login.js import Son from './Son.js'; class Login extends React.Component{ constructor(){ super(); this.handleChange=this.handleChange.bind(this); this.handleSubmit=this.handleSubmit.bind(this); this.state={ user:{ value:"", error:false }, pwd:{ value:"", error:false } } } handleChange(field,val){ let newState={value:val, error:true}; switch(field) { case "user": if (!val.length){ newState.error=false } else if (val.length>4) { newState.error=false } this.setState({ user:newState }) break; case "pwd": if (!val.length){ newState.error=false; } else if (val.length>6) { newState.error=false } this.setState({ pwd:newState }) break; } } handleSubmit() { let {user, pwd}=this.state; if (!user.error || !pwd.error) { alert("请重试!"); return; } else { $.ajax({ ... data: { username: user.value, password: pwd.value }, ... }) } render(){ let {user, pwd}=this.state; return( <Son title="请登陆" userValue={user.value} pwdValue={pwd.value} handleChange={this.handleChange} handleSubmit={this.handleSubmit} /> ) } }
相信各位看得出来,这是个登陆页面的雏形,其中仅限原理说明,先不要纠结规范什么的哈。。。通常来讲,既然有登陆,也就有注册,注册页面基本上也是这个道理。须要说明的是:子组件上的属性值和方法都是this.props的,这里之因此没有写this.handleChange或者this.handleSubmit是由于子组件自己没有这个方法,所以若是此时在子组件上的方法前加上this.xxx就会报错大概说这个方法不是个函数!属性值也类似;同时利用拆包表达式写this.props表示这些属性和方法都是从父组件上继承而来,只要父组件上定义了方法,所以子组件上此时能够不用写constructor()和super()。
这个场景主要用于组件嵌套比较多的时候。好比,咱们发如今子组件Son.js中,有三个输入框分别是用户名、密码,但貌似有点不三不四,那么咱们就完善一点这个表单:
class Form extends React.Component{ render(){ let {handleSubmit, userValue, pwdValue, handleChange}=this.props; return( <form onSubmit={handleSubmit} method="post" action="/submit"> <input type="text" name="user" value={userValue} onChange={(e)=>handleChange("user",e.target.value} /> <input type="password" name="pwd" value={pwdValue} onChange={(e)=>handleChange("pwd",e.target.value} /> <input type="submit" /> </form> ) } }
有了这个组件以后,关于表单的Son.js组件能够改形成(一样假定全部组件都在根目录下):
//Son.js import Form from './Form.js'; class Son extends React.Component{ render(){ let {title,userValue,pwdValue,handleChange,handleSubmit}=this.props; return( <div> <h3>{title}</h3> <Form userValue={userValue} pwdValue={pwdValue} handleChange={handleChange} handleSubmit={handleSubmit} /> </div> ) } }
也许新手童鞋们不太明白Son.js组件上的属性和方法命名究竟是不是必定要和孙子级组件上的同样,由于本人在学这个地方的时候的确纠结过,不过请注意:只要onChange或者onSubmit这类元素上原生方法后指定的一个函数(Form.js),好比onChange={handleChange},那么这个handleChange在传递的时候,上级组件(Son.js)上的handleChange={handleChange}中,左边是上级组件的方法,能够新命名好比footChange。。。而右边则是传递给下级组件的方法handleChange,因此,下级组件Form.js中onChange的右边函数名必须对应之。
此外,咱们还能够根据Son.js作个简单的欢迎页:
//Welcome.js class Welcome extends React.Component{ render(){ return( <h1>欢迎您!</h1> ) } }
//SonWelcome.js import Welcome from './Welcome.js'; class SonWelcome extends React.Component{ render(){ return( <div> <h3>{this.props.title}</h3> <Welcome /> </div> ) } }
固然,SonWelcom.js太过简单了。。。同时title的值依赖于上一级组件传值肯定,兄弟们大开脑洞吧。
相信这个状况是比较少的,不过这是个值得研究的,有一些师兄和大神们确定知道如何解决。所谓的兄弟组件就是具备共同的父组件或者“爷组件”的多个组件,这种状况和以上差很少,主要把兄弟组件之间须要的共同的值挂载到上级组件便可。而非上下级和非兄弟组件这种状况的应用场景有点相似(注意,仅仅是相似)session或者cookie,好比有多个页面须要根据用户是否登陆或者是不是管理员超级用户来对页面进行不一样的渲染。
先说说能够解决的途径吧,首先推荐的是一个js库:PubSubJs,详情能够去了解一下(实际我也没用过。。。)。其次,说说本人的想法吧。正如上所言,假设这个属性或者方法在渲染组件的时候并不涉及安全性问题,那么何不将其设置为cookie或者session呢?哪一个组件须要这个值就将其提出来。以下例两个组件:
暂且写以下,先无论自定义flag从何而来,同时,.active的样式是:display:none;
//CompOne.js class CompOne extends React.Component{ render(){ return( <div> <p className={flag? "":"active"}>这个第一个组件</p> </div> ) } }
//CompTwo.js class CompTwo extends React.Component{ render(){ return( <div> <p className={flag? "active":""}>这个第二个组件</p> </div> ) } }
假设以上两个组件并无关系,且都带有一个共同的自定义属性flag,这两个组件根据flag的意义进行隐藏或展现。此时,能够建一个组件Cookie内部封装一个构造函数HandleCookie,内部封装三个方法setCookie(name, value, time),getCookie(name),clearCookie(name, value, time)。假设,name是cookie名称,value是cookie的值,time参数是参照当前时间的cookie的保存时间长度,设置为1表示一天后过时,设置-1则表示过时失效。
照此假定,以上两个组件能够直接在渲染页面的时候取到cookie的flag名称对应的值,并根据值渲染页面。好比在项目的某个文件加载完毕(componentDidMount)的时候设置一个cookie:{flag:"1"},CompOne.js:
//CompOne.js import Cookie from './Cookie.js'; class CompOne extends React.Component{ render(){ let flag=Cookie.getCookie("flag"); return( <div> <p className={flag? "":"active"}>这个第一个组件</p> </div> ) } }
照此安排,这个组件CompOne渲染后就会展现,而CompTwo则会隐藏。不过,这种方式明显不是一种规范的方法,仅仅是想法而已,望轻喷!
以上如有不当之处,还请指正一下,给小弟一个改过自新的机会吧。。。若是童鞋还对其余没有写完全的地方感兴趣,能够参见本人的一个留言本小项目,乃是本国reactjs、webpack配置、nodejs和express入门的最好材料之一,以为好用就star一下吧,哎,求star真很差意思^_^