为啥react-router中的link用不了
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为啥react-router中的link用不了相关的知识,希望对你有一定的参考价值。
参考技术A 其实例子里的代码已经很老了,React Router 的 API 也发生了很多变化。因此今天抽出一晚上的时间,再以最新的 React Router 稳定版(截止 2015年08月18日21:23:40 为 v0.13.3 版,与 React 版本号一致)为基础讲讲如何使用 React Router。阅读本文需要你有一定的 ReactJS 基础,如果你正在寻找 ReactJS 中文入门教程,推荐我参与翻译的 React - 引领未来的用户界面开发框架 一书。
快速上手
一个最基本的页面,菜单有「图书」和「电影」两个菜单项,点击「图书」显示图书列表(链接变为/books),点击「电影」显示电影列表(链接变为/movies)。
Demo
说实话,这个例子并不简单。下面逐步分析一下用到的代码和它们分别是干什么的。
var Router = ReactRouter; // 由于是html直接引用的库,所以 ReactRouter 是以全局变量的形式挂在 window 上
var Route = ReactRouter.Route;
var RouteHandler = ReactRouter.RouteHandler;
var Link = ReactRouter.Link;
var StateMixin = ReactRouter.State;
由于 Demo 需要直接从网页上引用 React 和 React Router,因此它们都被挂在了 window 对象上(现在但凡有点追求的前端都上 webpack 了,但是例子的话大家就将就着看吧)。这几行就是获取 ReactRouter 提供的几个组件和 mixin。
接下来声明了 4 个组件,都是最基本的只有 render 方法的 React 组件,分别是: Movies 电影列表 、 Movie 电影详情 、 Books 图书列表 、 Book 图书详情 。
关于组件唯一需要说明的是用到了 ReactRouter 提供的 State 这个 mixin,主要功能就是让组件能够通过 this.getParams() 或 this.getQuery() 等方法获取到当前路由的各种值或参数。
然后是应用的入口,也是我们渲染菜单的地方:
// 应用入口
var App = React.createClass(
render: function()
return (
<div className="app">
<nav>
<Link to="movies">电影</Link>
<Link to="books">图书</Link>
</nav>
<section>
<RouteHandler />
</section>
</div>
);
);
这里用到了两个 ReactRouter 提供的组件: Link 和 RouteHandler 。
Link 组件可以认为是 ReactRouter 提供的对 <a> 标签进行封装的组件,你可以查看 Link 组件渲染到 DOM 上其实就是 a 标签。它接受的 props 有 to、params 和 query。to 可以是一个路由的名称(下文会讲到),也可以是一个完整的 http 地址(类似 href 属性);params 和 query 都是这个链接带的参数,下文细讲。
此外,Link 组件还有一个小特点,就是如果这个 Link 组件指向的路由被激活的话,组件会自动添加一个值为 active 的 className,方便你对当前激活的菜单项设置不同的样式(注意 demo 中红色的菜单项)。
而 RouteHandler 组件是 ReactRouter 的核心组件之一,它代表着当前路由匹配到的 React 组件。假设当前的路由为 /books ,那么 App 这个组件里的 RouteHandler 其实就是 Books 组件。
那么这个关系是怎么得来的呢?就要看下面定义的页面路由了。
// 定义页面上的路由
var routes = (
<Route handler=App>
<Route name="movies" handler=Movies />
<Route name="movie" path="/movie/:id" handler=Movie />
<Route name="books" handler=Books />
<Route name="book" path="/book/:id" handler=Book />
</Route>
);
这里又出现了另外一个 ReactRouter 提供的组件 Route ,这个组件就是定义整个页面路由的基础,可以嵌套。
Route 接受的 props 包括 name、path、handler 等等。其中 name 就是上文提到的路由名称,可以通过 <Link to="路由的名称"> 来生成一个跳转到该路由的链接。path 指明的是当前路由对应的 url,如果不指定,那么默认就是 name 对应的值;如果 name 也不指定,那默认是 / ,即根目录。另外 path 还支持指定 params(上文有提到),就是上面的例子中 : 及后面跟着的名称。
params 和 query 的区别在于,params 定义的是「路由」中的参数,比如 /movies/:id ,params 为 id;而 query 是 「URL」中的参数,是跟在 URL 中「?」后面的。定义路由时一般不考虑也不能限制 query 会是什么。
比如 <Route name="movies" handler=Movie /> 就指明了一条指向 /movies 的路由,当该路由激活时,调用 Movies 这个组件进行渲染。
接下来就是最后一步,根据上面定义的路由判断出当前该渲染哪个组件,并将其渲染到 DOM 中。
// 将匹配的路由渲染到 DOM 中
Router.run(routes, Router.HashLocation, function(Root)
React.render(<Root />, document.body);
);
Router 即 ReactRouter,run 方法接受 2 - 3个参数,其中第一个参数必填,即我们指定的路由规则。第二个参数选填,即路由的实现方式, Router.HashLocation 指明了当前页面使用 hash 变化来实现路由,反映在浏览器的地址栏中就是类似 xxx.com/#/movies 这样的地址。使用这种 Location 的好处是兼容 IE 8,如果你的应用不需要兼容 IE 8,可以使用更高级的 Router.HistoryLocation 。
最后一个参数是一个回调函数,函数的第一个参数是 ReactRouter 判断出的当前路由中需要渲染的根节点组件,在这里就是 <App /> 这个组件(虽然名字叫做 Root,但在本例中 Root 指的就是 App)。
如何使用 React-Router 的服务器端渲染中的 <Link> 标签更改 StaticRouter 的位置道具
【中文标题】如何使用 React-Router 的服务器端渲染中的 <Link> 标签更改 StaticRouter 的位置道具【英文标题】:How to change StaticRouter's location prop using the <Link> tag in Server Side Rendering with React-Router 【发布时间】:2018-05-03 04:52:04 【问题描述】:已经有效的方法:
主页上的服务器端渲染。
什么不起作用:
通过单击<Link>
标签转到其他路由,从主页在其他其他路由上进行服务器端渲染。好吧,有点不工作,同时工作。
工作方式?:
如果您在单击<Link>
后查看页面的页面源,您将看到服务器端渲染获取的所有初始数据,但是它没有存储在客户端的reducer 中。
解决方案?:
通过大量时间和研究和询问,我得出的结论是,问题出在服务器端的StaticRouter
。特别是 location
道具。此道具通过req.path
或req.url
,我都尝试过并得到相同的结果。我将以req.path
为例。
让我们看看这里的这段代码:
console.log(req.path);
const content = renderToString(
<Provider store=store>
<StaticRouter location=req.path context=context>
<div>renderRoutes(routes)</div>
</StaticRouter>
</Provider>
);
在这里,我们在将 req.path
传递给 location
属性之前注销它。这就是我认为告诉路由器将正确的数据加载到存储中并将其发送到客户端减速器的原因。
我将逐步说明应用流程发生的情况。
在/
路由加载console.log(req.path)
在服务器端显示此:
/
但是,例如,如果我单击 <Link to="/users">Users</Link>
,控制台日志什么也不做。
现在我可以从这里刷新页面,然后它就可以工作了,数据已加载,console.log(req.path)
显示:
/users
我可以做的其他事情是直接转到localhost:3000/users
的路线,console.log(req.path)
将显示/users
并且数据正确加载。但这两种方式都不是真正的解决方案,只是因为它们以某种方式“绕过”了<Link>
标签。
问题是什么???:
我想知道如何使用<Link>
标签来更改req.path
或req.url
,因为这是我所看到的问题,或者是否有可能。这样StaticRouter
中的location
属性会在<Link>
被点击时改变。
【问题讨论】:
【参考方案1】:这段代码:
console.log(req.path);
const content = renderToString(
<Provider store=store>
<StaticRouter location=req.path context=context>
<div>renderRoutes(routes)</div>
</StaticRouter>
</Provider>
);
在服务器端执行,它发生在您登陆站点、通过键入 url 直接访问某个页面或刷新页面时,因为在这些情况下,您“要求”服务器为您进行渲染。
<Link>
用于浏览器端的导航,它不要求服务器做任何事情,它都是在浏览器中执行的,所以它永远不会触发console.log(req.path);
。除非您明确地这样做,例如,使用类似location.reload();
的代码以编程方式刷新页面。在我看来,如果你觉得有必要做这样的事情,你就没有抓住重点。
s-s-r - 长话短说:
我们使用 s-s-r,因此当我们登陆页面时,我们不会等待初始 HTML 和初始数据。我们可以将服务器上的组件渲染成静态模型,而不是发送空白页面并让浏览器完成所有工作,然后将包含重新填充数据的页面发送到浏览器。当 bundle.js 出现时,浏览器从那时起接管,负责导航和加载交互所需的任何内容。
使用 s-s-r 的一些好处是 快速首次绘制,这可以带来更好的用户体验和潜在的更好的 SEO,因为爬虫更好地读取从服务器发送的静态模型而不是生成的动态模型客户。
【讨论】:
经过一些研究并认为这是我得出的结论,除了重新加载之外还有其他方法吗?因为在这种情况下,我还不如使用<a>
标签,或者只是通过操作加载数据客户端。但正如我所说,这可能是不可能的。那是你说的吗?
你想通过服务器重新加载来完成什么?如果它正在更新您的商店,获取数据,那是客户端应该对 Link 更改的导航状态执行的操作。
但这违背了做 s-s-r 的全部目的,不是吗?
不是,我们使用 s-s-r,所以当我们登陆页面时,我们不会等待初始 HTML 和初始数据。我们可以将服务器上的组件渲染成静态模型,而不是发送空白页面并让浏览器完成所有工作,然后将包含重新填充数据的页面发送到浏览器。当 bundle.js 出现时,浏览器从那时起接管,负责导航并加载交互所需的任何内容。
您能否将此添加到您的答案中,我会接受。此外,我发现在其他路线上进行 s-s-r 仍然有利于 SEO 的东西,比如爬虫等等。包括这个,我会接受答案并给你赏金以上是关于为啥react-router中的link用不了的主要内容,如果未能解决你的问题,请参考以下文章
为啥vue中子路由点击router-link只能刷新一次子页面?
如何使用 React-Router 的服务器端渲染中的 <Link> 标签更改 StaticRouter 的位置道具
无法使用 Link 组件传递状态。为啥状态未定义? [复制]