使用 React-Router 的时候遇到一个问题

2017/05/25 | 2分钟阅读 | 更新于 2017/05/25

利用 React 编写 Markdown 编辑器(的时候遇到了一个问题)。

最近在写一个博客系统,其中后端部分用了 Koa2,目前基本完成。前端(管理)部分因为正在熟悉 React,采用了 React 编写。因为不需要考虑兼容性,Ajax 请求使用 Fetch API 实现。

整个编辑器本身作为一个组件或称视图,包含了两个子组件,基于 CodeMirror 代码编辑器组件和基于 Marked 渲染组件。

然后 React 的思想大致是数据仅由高到低单向流动,父组件可以传个方法给子组件,用于(让父组件自己)更新值。简单画个图的话大致长这个样子:

草图

理论上这样没有问题,实际上写起来也是这样,不过在我给 React-Router 加入了嵌套路由之后,就发生了一些微妙的变化。

是这样的,我的编辑器在 /edit 这个路由的位置上,然后如果我想在点击某篇文章之后跳转编辑这篇文章,很自然的就想到了 /edit/:id 这个办法。但是实际情况下,我发现编辑器两边都没有值,但是编辑器本身的输入和渲染是 ok 的。感觉原因应该出在请求博客内容之后,更新父组件的 state 的时候。但是更新 state 和编辑器组件是调用的同一个 setMarkdown 方法,结果应该一致的。

难道没有请求到内容?于是在组件初始位置输出了 id。嗯??为什么会有两个 id 出现,一个 undefined,另一个有值。不只是这个,所有的东西都是两份,包括 state 也有不同的两版。

为什么一个组件会挂载两次?一组有id,一组没有id?嗯?id?好吧,原因跟 React-Router 的匹配机制有关。这货会自上而下的匹配,而我恰巧把 /edit/:id 的 Route 写在了 /edit 的下方导致实际挂载的是没有id的版本。于是我把两个 Route 调换过来,嗯,成功出现内容。

但是 CodeMirror 那边内容没法更新,需要调用 CodeMirror 预留的 setValue 方法。关于如何选择更新时机就又是一个问题了,props 每次变动都更新的话就不用编辑了,因为覆盖更新的话,每输入一次,光标每次都会跑到最前部。理论上能用增量更新,CodeMirror 有相关的方法好像。不过我选择了一个更简单的办法,加了一个 props.done 标记内容加载完成,当值变更时获取 props.raw 覆盖更新。

【接↑↑段】你以为是这个原因吗?那么如何解释挂载了两次呢?其实是 /edit/xxxx 会同时匹配 /edit/:id/edit,但是 /edit 只会匹配 /edit,然后我把两个 Route 写在同一级了,导致带有 id 的情况下一次挂载了两个组件,而不带 id 的时候其实只会挂载一个组件。我是在写 Demo 验证的时候发现的,这个可用在浏览器中看到DOM变动。

具体细节感觉还需要了解,合理的解法感觉可以把 /edit/* 移动到组件内部去继续判断。话说居然已经 1:10 了,白天起床再研究好了。

© 2026 香蕉引擎故障报告

🌱 Powered by Hugo with theme Dream.

关于

要怎么介绍自己呢,🤔。

很早以前是作为 Web 前端在学习的,但是工作第一年就成为了全干工程师。喜欢尝试各种东西,什么都会一点。

一直很喜欢 Ebiten 游戏引擎 ,特别简洁,用它做过一些小东西,可以查看这个分类 。另外特别推荐这个木鱼 ,是一个相对完整的小玩意儿,包含手搓的一个简单的 UI 框架;支持鼠标和键盘操作;有多语言和主题切换功能;同时支持 Web 端和客户端。它的源代码在 bin16/wooden-fish

主题

网站基于 Hugo,当前使用的是 hugo-theme-dream 主题的修改版 ,根据我的需要,做了一些对 PaperMod 的兼容。

我自己也写过主题 ,但是没有别人写的好看。

正在从我的笔记中往外搬运内容

等待更新:

  • 从《锈湖》中学了些什么东西
  • 我拿 React 写解谜游戏的经过
  • 基于 Pocketbase 的 Pocket Memos
  • 数独!