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

React Native中如何用JSON Form Schema自定义渲染UI并集成Yup验证?

在React Native中实现JSON Schema表单+自定义渲染器+Yup验证

完全可以实现,现成包满足不了需求的话,自己搭建核心逻辑反而更灵活,能精准匹配你的UI和验证需求。以下是具体实现思路和代码示例:

1. 定义适配的JSON Schema结构

先定义包含UI元数据、字段类型和验证映射的Schema,比如:

{
  "fields": [
    {
      "name": "username",
      "label": "用户名",
      "type": "text",
      "placeholder": "请输入用户名",
      "yupRule": "required|min:3|max:20"
    },
    {
      "name": "email",
      "label": "邮箱",
      "type": "email",
      "placeholder": "请输入邮箱",
      "yupRule": "required|email"
    },
    {
      "name": "age",
      "label": "年龄",
      "type": "number",
      "placeholder": "请输入年龄",
      "yupRule": "required|min:18|max:100"
    },
    {
      "name": "acceptTerms",
      "label": "同意服务条款",
      "type": "boolean",
      "yupRule": "required|isTrue"
    }
  ]
}

2. 实现自定义字段渲染器

创建一个FormFieldRenderer组件,根据Schema中的type渲染对应的React Native UI元素:

import React from 'react';
import { View, Text, TextInput, Switch, StyleSheet } from 'react-native';

const FormFieldRenderer = ({ field, value, onChange, error }) => {
  const handleChange = (val) => {
    onChange(field.name, field.type === 'number' ? Number(val) : val);
  };

  return (
    <View style={styles.fieldContainer}>
      <Text style={styles.label}>{field.label}</Text>
      {field.type === 'text' || field.type === 'email' ? (
        <TextInput
          style={[styles.input, error && styles.errorInput]}
          placeholder={field.placeholder}
          value={value?.toString() || ''}
          onChangeText={handleChange}
          keyboardType={field.type === 'email' ? 'email-address' : 'default'}
        />
      ) : field.type === 'number' ? (
        <TextInput
          style={[styles.input, error && styles.errorInput]}
          placeholder={field.placeholder}
          value={value?.toString() || ''}
          onChangeText={handleChange}
          keyboardType="numeric"
        />
      ) : field.type === 'boolean' ? (
        <View style={styles.switchContainer}>
          <Switch
            value={value || false}
            onValueChange={handleChange}
          />
        </View>
      ) : null}
      {error && <Text style={styles.errorText}>{error}</Text>}
    </View>
  );
};

const styles = StyleSheet.create({
  fieldContainer: { marginBottom: 16 },
  label: { fontSize: 14, fontWeight: '500', marginBottom: 8 },
  input: { borderWidth: 1, borderColor: '#ccc', borderRadius: 8, padding: 12, fontSize: 16 },
  errorInput: { borderColor: '#ff4444' },
  switchContainer: { flexDirection: 'row', alignItems: 'center' },
  errorText: { color: '#ff4444', fontSize: 12, marginTop: 4 }
});

export default FormFieldRenderer;

3. 集成Yup表单验证

编写工具函数将Schema中的yupRule转换为Yup验证规则,然后在表单中处理验证逻辑:

import React, { useState } from 'react';
import { View, Button, StyleSheet } from 'react-native';
import * as Yup from 'yup';
import FormFieldRenderer from './FormFieldRenderer';
import formSchema from './formSchema.json';

// 转换Schema规则为Yup Schema
const buildYupSchema = (fields) => {
  const yupShape = {};
  fields.forEach(field => {
    let yupField = Yup.mixed();
    const rules = field.yupRule?.split('|') || [];
    
    rules.forEach(rule => {
      const [ruleName, ruleValue] = rule.split(':');
      switch(ruleName) {
        case 'required':
          yupField = yupField.required(`${field.label}不能为空`);
          break;
        case 'min':
          yupField = field.type === 'number' 
            ? yupField.min(Number(ruleValue), `${field.label}不能小于${ruleValue}`)
            : yupField.min(Number(ruleValue), `${field.label}长度不能小于${ruleValue}位`);
          break;
        case 'max':
          yupField = field.type === 'number' 
            ? yupField.max(Number(ruleValue), `${field.label}不能大于${ruleValue}`)
            : yupField.max(Number(ruleValue), `${field.label}长度不能大于${ruleValue}位`);
          break;
        case 'email':
          yupField = yupField.email(`${field.label}格式不正确`);
          break;
        case 'isTrue':
          yupField = yupField.oneOf([true], `${field.label}必须同意`);
          break;
        default:
          break;
      }
    });
    
    yupShape[field.name] = yupField;
  });
  return Yup.object().shape(yupShape);
};

const CustomSchemaForm = () => {
  const [formValues, setFormValues] = useState({});
  const [errors, setErrors] = useState({});
  const yupValidationSchema = buildYupSchema(formSchema.fields);

  const handleFieldChange = (name, value) => {
    setFormValues(prev => ({ ...prev, [name]: value }));
    // 实时清除对应字段错误
    if (errors[name]) {
      setErrors(prev => ({ ...prev, [name]: undefined }));
    }
  };

  const handleSubmit = async () => {
    try {
      await yupValidationSchema.validate(formValues, { abortEarly: false });
      // 验证通过,处理提交逻辑
      console.log('表单数据:', formValues);
    } catch (err) {
      const newErrors = {};
      err.inner.forEach(error => {
        newErrors[error.path] = error.message;
      });
      setErrors(newErrors);
    }
  };

  return (
    <View style={styles.container}>
      {formSchema.fields.map(field => (
        <FormFieldRenderer
          key={field.name}
          field={field}
          value={formValues[field.name]}
          onChange={handleFieldChange}
          error={errors[field.name]}
        />
      ))}
      <Button title="提交" onPress={handleSubmit} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20, marginTop: 40 }
});

export default CustomSchemaForm;

扩展说明

  • 可以根据需求扩展更多字段类型(比如Picker、日期选择器),只需要在FormFieldRenderer中添加对应分支即可。
  • 如果需要更复杂的UI自定义,可以在Schema中增加customProps字段,传递给渲染组件。
  • 验证规则可以直接在Schema中定义Yup规则对象,代替字符串拆分,更灵活。

内容的提问来源于stack exchange,提问作者Praful Kadam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 09:35:38