React主要功能在于渲染HTML。可以将其看成是MVC中的V,它不会影响到组件中直接调用AJAX请求之类的操作:
var TakeSurvey=React.CreateClass({ getInitialData:function(){ return{ survey:null }; }, componentDidMount:funciton(){ $.getJSON('/survey/'+this.props.id,function(json){ this.setState({survey:json}); }); }, render:function(){ return <div>{this.state.survey.title}</div> } });
路由在单页面应用里为URL指定处理器函数。假设要为URL/surveys运行一个函数,函数的功能是从服务器加载用户,然后渲染<LIstSurveys>组件。
路由有很多种,在服务器端也存在路由,有一些路由可以在客户端和服务器端运行。
React仅仅是一个一个的渲染类库,没有路由的功能,不过有很多路由模块可以搭配React使用。
1、Backbone.Router:
Backbone是单页面应用类库,采用了MVX(Model-View-Whatever)架构。其中X指代控制器(Controller),通常指代的是路由。对Backbone来说就是如此。
Backbone是模块化,你可以只用它的路由功能。它可以和React很好的搭配在一起使用。例如:
var SurveysRouter =Backbone.Router.extend({ routes:{ "surveys":"list" }, list:function(){ React.renderComponent( <ListSurveys />, document.querySelector('body') ); } });
路由需要处理URL中动态的部分和queryString。Backbone.Router具备这样的功能,示例如下:
varSurveysRouter=Backbone.Router.extend({ routes:{ "surveys":"list", "surveys/:filter":"list" }, list:function(filter){ React.renderComponent( <ListSurveys filter={filter}/>, document.querySelector('body) ); }, });
在上面的例子中,给定一个比如/surveys/active这样的URL地址,那SurveysRouter#list的参数filter就是active。
2、Aviator
与Backbone.Router不同,Aviator是一个独立的路由类库。
在Aviator中,路由定义与RoutetTarget是相互独立的。即Aviator不关心RouteTarget的实现和行为,仅试着调用赋值在它上面的方法。
比如这样一个RouteTarget:
//surveys_route_target.js varSurveysRouteTarget={ list:function(){ React.renderComponent( <ListSurveys>, docment.querySelector('body'); ); } };
与这个对象对应,需要有一份路由的配置(整个应用只能有一个唯一的路由配置),这个配置通常写在另一个独立的文件中。
//routes.js
Aviator.setRoutes({
'/surveys':{
target:UsersRouteTarget,
'/':'list'
}
});
//让Aviator把url分派到RouteTarget
Aviator.dispatch();
设置RouteTarget处理函数:
//route.js Aviator.setRoutes({ '/surveys':{ target:usersRouteTarget, '/':'list', '/:filter':'list' } }); //surveys_route_target.js varSurveysRouteTarget={ list:function(request){ React.renderComponent( <ListSurveys filter={request.param.filter}/>, doucument.querySelector('body') ); } }
Aviator有一个很棒的特性就是可以使用多个RouteTarget,例如下main这样的路由配置:
//route.jsAviator.setRoutes({ target:AppRouteTarget, '/*':beforeAll, '/surveys':{ target:UsersRouteTarget, '/':'list' '/:filter':'list' } });
对于'/surveys/active'这样的URL,Aviator会先调用appRouteTarget.before.veforeAll在调用UsersRouteTarget.list——只要匹配,Action的数量并不受限制。你还可以定义路由离开时的执行函数,当用户从匹配的路由离开时,定义过的执行函数会从内到外以此执行。
3、react-router
react-router不同于其他的路由,它完全是有ReactComponent构成的。路由被定义成了组件,路由的处理器也是组件。按照react-router的写法路由是这样的:
var appRouter=( <Routes location="history"> <Route title="SurveyBuilder" handler={App}> <Route name="list" path="/"handler={ListSurveys}/} <Route title ="Add Survey to SurveyBuilder"name="add" path="/add_survey" handler={AddSurvey}/> <Route name ="edit" path="/surveys/:surveyId/edit" handler={EditSurvey}/> <Route name="take" path="/surveys/:surveyId"handler={TakeSurveyCtrl} /> <NotFound title="page Not Found"handler={NotFoundHandler}/> </Route> </Routes> );
每一个处理器就是一个对应着特定页面的组件。把上面的路由作为顶层的组件渲染来启动它。
React.renderComponent(
appRouter,
document.querySelector('body')
);
就像其他的路由一样,react-router也有类似的参数概念。 比如路由‘/surveys/:surveyId'会把surveyId属性传给TakeSurveyCtrl组件。
Link是react-router提供的很酷的特性之一。你可以使用它来导航,它可以自己对应到路由上。而且它还能自动给链接添加active样式,标记当前活动页面。
使用react-routerLink组件后<MainNav/>组件看起来是这样的:
varMainNav=React.createClass({ render:function(){ retrun( <nav className='main-nav' role='navigation'> <ul className='nav navbar-nav'> <li><Link to='list'>All Surveys </link></li> <li><Link to="add" >AddSurvey</Link></li> </ul> </nav> ); } });
4、Om(ClojureScript)
Om是比较流行的React的CloujureScipt接口。通过clojureScript的不可变数据结构,Om可以飞快地重新渲染整个应用,而且每个操作都可以很容易的村委快照,用来实现撤销等功能。
Om组件看起来是这样:(ns example
(:require[om.core :as om :include-macros true] [om.dom:as dom :include-macros true])) (defn App[data owner] (reify om/IRender(render[this] (dom/h1 nil (:text data))))) (om/rootApp {text "Survey Builder"} {:targer(. js/document (querySelector "body"))})
它将被渲染为<h1>SurveyBuilder</h1>