如何避免Inertia发起POST请求后触发页面重渲染
问题背景
在Laravel + Vue(基于Inertia.js)技术栈搭建的工单系统中,全量工单列表页的后端控制器代码如下:
public function index(): Response { $tickets = Tickets::all(); return Inertia::render('Dashboard/Issues/Index', compact('tickets')); }
前端页面内编写的新增工单逻辑代码如下:
const addTicket = () => { Inertia.post('/dashboard/ticket', ticket); tickets.push(ticket); }
后端对应工单创建接口的控制器代码如下:
public function store(Request $request) { $this->ticketCreator->create($request->all()); }
异常表现
发起新增工单的POST请求后,页面会触发整页重载,自动发起GET请求拉取全量页面内容,请求时序表现如下图:
现有逻辑已经通过tickets.push(ticket);实现了本地列表数据更新,不需要Inertia后台触发页面重渲染。
产生原因
- Inertia.js的默认请求规则要求:所有非GET类型的Inertia请求,后端必须返回合法的Inertia响应、或者重定向响应;如果接口无返回、或者返回非Inertia规范的普通响应,Inertia会自动触发整页硬重载,也就是观察到的自动拉取全量页面的现象。当前
store方法执行完创建逻辑后没有返回任何响应,直接触发了该默认硬重载逻辑。 - 现有前端代码存在时序问题:Inertia请求是异步执行的,发起请求后立刻执行
tickets.push()不会等待后端返回结果,如果后端创建失败、参数校验不通过,会直接导致前端本地数据和服务端数据不一致。 - 附带代码笔误:原前端Inertia请求的路径参数缺少闭合单引号,会直接导致JS语法报错。
规避方案
根据需求可以选择以下两种方案实现无重载的新增逻辑:
- 方案1:保留Inertia请求,配置禁止状态替换
后端store方法执行完创建逻辑后返回回退重定向响应,前端发起请求时开启preserveState配置,禁止Inertia用服务端返回的新状态覆盖本地状态,同时将本地数据更新逻辑放到请求成功回调中,保证数据一致性:// 后端store方法修改 public function store(Request $request) { $this->ticketCreator->create($request->all()); return back(); }
该配置下Inertia收到后端重定向响应后,不会重新拉取列表页全量数据替换本地状态,不会触发页面重载。// 前端新增方法修改 const addTicket = () => { Inertia.post('/dashboard/ticket', ticket, { preserveState: true, preserveScroll: true, onSuccess: () => { // 后端创建成功后再更新本地列表 tickets.push(ticket); } }) } - 方案2:绕过Inertia发起普通异步请求
如果不需要Inertia介入该请求的路由、状态处理逻辑,直接使用axios/fetch发起普通XHR请求即可,该方式完全不会触发Inertia的默认行为,请求成功后更新本地列表即可:const addTicket = async () => { // 可直接使用项目内全局挂载的axios实例 await axios.post('/dashboard/ticket', ticket) tickets.push(ticket) }
注意:无论使用哪种方案,都必须等待后端返回创建成功的响应后再更新本地列表,避免插入脏数据。
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

