> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Precognition

> 在表单提交前实时执行服务端校验的 Laravel 功能。

## 什么是 Precognition

Precognition 是一种在表单提交之前执行服务端校验的机制。
你无需在前端重复定义校验规则，可以直接使用 Laravel 的规则。

与普通请求不同，Precognition 请求会执行路由中间件与 Form Request 的校验，但不会执行控制器方法主体。
因此非常适合在输入过程中进行实时校验。

## 安装

在 Laravel 13 中，后端无需额外安装 `laravel/precognition`。
你只需要安装用于前端的辅助包。

* Vue：`laravel-precognition-vue`
* React：`laravel-precognition-react`
* Alpine.js：`laravel-precognition-alpine`

```shell theme={null}
npm install laravel-precognition-vue
```

```shell theme={null}
npm install laravel-precognition-react
```

```shell theme={null}
npm install laravel-precognition-alpine
```

<Info>
  Inertia 自 2.3 起内置支持 Precognition，Inertia 3 也可直接使用。
  在使用 Inertia 表单时，通常不需要额外引入 `laravel-precognition-vue` / `laravel-precognition-react`。
</Info>

## 后端配置

给路由添加 `HandlePrecognitiveRequests` 中间件。
将校验规则集中在 Form Request 中是实践性的做法。
使用 Form Request 更便于规则复用和职责分离。

```php theme={null}
use App\Http\Requests\StoreUserRequest;
use Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests;
use Illuminate\Support\Facades\Route;

Route::post('/users', function (StoreUserRequest $request) {
    // 只有在真正提交时才会执行此处
})->middleware([HandlePrecognitiveRequests::class]);
```

如果你自定义的中间件有副作用，请在 Precognition 时跳过。

```php theme={null}
public function handle(Request $request, Closure $next): mixed
{
    if (! $request->isPrecognitive()) {
        Interaction::incrementFor($request->user());
    }

    return $next($request);
}
```

## 前端集成

### Alpine.js（Blade）

```html theme={null}
<form x-data="{
    form: $form('post', '/users', { name: '', email: '' }),
}">
    @csrf
    <input x-model="form.name" @change="form.validate('name')" />
    <template x-if="form.invalid('name')">
        <div x-text="form.errors.name"></div>
    </template>
</form>
```

### Vue（Inertia.js）

```vue theme={null}
<script setup>
import { useForm } from 'laravel-precognition-vue';

const form = useForm('post', '/users', {
    name: '',
    email: '',
});
</script>

<template>
    <input v-model="form.name" @change="form.validate('name')" />
    <div v-if="form.invalid('name')">{{ form.errors.name }}</div>
</template>
```

### React（Inertia.js）

```jsx theme={null}
import { useForm } from 'laravel-precognition-react';

const form = useForm('post', '/users', {
    name: '',
    email: '',
});

<input
    value={form.data.name}
    onChange={(e) => form.setData('name', e.target.value)}
    onBlur={() => form.validate('name')}
/>
```

### 使用 Axios 的原生 JS

Precognition 库使用 Axios。
如果你希望使用已有的 Axios 实例，可以通过 `client.use()` 替换。

```js theme={null}
import Axios from 'axios';
import { client } from 'laravel-precognition-vue';

window.axios = Axios.create();
window.axios.defaults.headers.common['Authorization'] = authToken;

client.use(window.axios);
```

## 控制校验时机

对逐个字段的校验使用 `validate()`。

```js theme={null}
form.validate('email');
```

防抖时间可以通过 `setValidationTimeout()` 调整。

```js theme={null}
form.setValidationTimeout(3000);
```

如果希望每次都校验文件，请使用 `validateFiles()`。

```js theme={null}
form.validateFiles();
```

对数组输入可以使用通配符校验。

```js theme={null}
form.validate('users.*.email');
```

## 表单辅助函数

`useForm()` 可以整体管理提交与错误状态。

* `validating`：正在发起校验请求
* `processing`：正在提交
* `errors`：错误列表
* `valid('field')` / `invalid('field')`：字段校验状态
* `submit()`：常规提交

```js theme={null}
const submit = () => form.submit()
    .then(() => form.reset());
```

## 普通请求与 Precognition 请求的对比

下图展示了普通请求与 Precognition 请求的处理差异。

```mermaid theme={null}
sequenceDiagram
    participant User as 用户
    participant Frontend as 前端
    participant Server as Laravel 服务器

    User->>Frontend: 表单输入
    Frontend->>Server: Precognition 请求（携带 Precognition: true 头）
    Server->>Server: 执行校验（不执行控制器逻辑）
    Server-->>Frontend: 校验结果
    Frontend-->>User: 实时展示错误
    User->>Frontend: 提交表单
    Frontend->>Server: 普通请求
    Server-->>Frontend: 响应
```

## 相关链接

* [Laravel 官方：Precognition](https://laravel.com/docs/precognition)
* [Laravel 官方：Validation](https://laravel.com/docs/validation)
