You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel SPA中Inertia.js与Vue.js嵌套组件响应性问题

Inertia.js + Laravel + Vue3 SPA 新增Todo后组件无法自动更新数据

问题场景

使用Inertia.js构建Laravel+Vue3单页应用时,原本在Home页面直接渲染todos列表,新增Todo后数据能正常更新;但拆分出TodoList组件负责渲染后,新增的Todo必须手动刷新页面才会显示,TodoList接收的todos props无法响应式更新,尝试用ref包裹props也无效。

核心原因

当前后端store方法执行完成后直接重定向回首页,Inertia默认会复用之前页面的props缓存,不会重新请求最新的todos数据,导致组件拿到的仍是旧数据。

解决方案(两种可选)

方案1:后端重定向时强制刷新数据

修改TodoController.php的store方法,在重定向时添加X-Inertia-Refresh请求头,让Inertia重新获取首页的最新props:

class TodoController extends Controller
{
    public function index()
    {
        return Inertia::render('Home', [
            'todos' => Todo::latest()->get()->toArray(),
        ]);
    }

    public function store(Request $request)
    {
        Todo::create([
            'task' => $request->input('task'),
        ]);

        return redirect()->route('index')->withHeaders([
            'X-Inertia-Refresh' => true,
        ]);
    }
}

此方式会让Inertia重新调用index方法获取最新todos,页面组件自动更新数据。

方案2:前端提交成功后手动更新本地数据(更优SPA体验)

无需重定向,直接在前端将新创建的Todo添加到本地列表,避免页面重新加载:

  1. 修改后端store方法,返回新创建的Todo数据:
public function store(Request $request)
{
    $todo = Todo::create([
        'task' => $request->input('task'),
    ]);

    return response()->json($todo, 201);
}
  1. 修改Home.vue,将props转为响应式变量并定义更新方法:
<template>
    <TodoList :todos="todos" @add-todo="addTodoToList" />
</template>

<script setup>
import TodoList from "./TodoList.vue";
import { ref } from 'vue';

const props = defineProps(["todos"]);
// 将props中的todos转为本地响应式数组
const todos = ref([...props.todos]);

// 向列表头部添加新Todo(对应后端latest()排序)
const addTodoToList = (newTodo) => {
    todos.value.unshift(newTodo);
};
</script>
  1. 修改TodoList.vue,传递事件到子组件:
<template>
    <div class="w-2/3 flex flex-col justify-center">
        <!-- 必须添加key,确保Vue正确跟踪列表项变化 -->
        <Todo v-for="todo in todos" :key="todo.id" :todo="todo" @add-todo="$emit('add-todo', $event)" />
    </div>
</template>

<script setup>
import Todo from "./Todo.vue";

defineProps(["todos"]);
defineEmits(['add-todo']);
</script>
  1. 修改Todo.vue,提交成功后触发事件传递新Todo:
<template>
    <form @submit.prevent="addTodo" class="relative">
        <input
            class="p-3 pr-12 w-full rounded-md"
            type="text"
            name="todo"
            id="todo"
            placeholder="Create a new todo..."
            v-model="todoForm.task"
        />
        <button
            class="absolute text-white flex justify-center items-center top-1 right-1"
        >
            <span
                class="text-white bg-indigo-600 rounded-full text-5xl h-10 w-10 leading-[30px]"
                >+</span
            >
        </button>
    </form>
</template>

<script setup>
import { useForm } from "@inertiajs/vue3";

const emit = defineEmits(['add-todo']);
const todoForm = useForm({
    task: "",
});

const addTodo = () => {
    todoForm.post("/todos", {
        onSuccess: (response) => {
            todoForm.reset("task");
            // 将新Todo传递给父组件更新列表
            emit('add-todo', response.data);
        },
    });
};
</script>

内容的提问来源于stack exchange,提问作者Med Amine Grid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 01:46:22