React共享状态下JSON/YAML编辑器无法新增键值的问题解决需求
JSON与YAML编辑器共享React状态时无法新增键值对的解决方案
问题描述
当JSON编辑器与YAML编辑器共享并更新同一React状态时,无法在任一编辑器中新增键值对,需要实现双向实时同步,支持新增、修改键值对。
组件代码
父组件(通过props传递JSON数据给子组件)
import * as React from 'react'; import Editors from './Editors'; const jsonData = { name: 'name', email: 'email', phone: [123, 234, 345], location: 'location', country: 'country', show: true, }; export default function App() { return ( <div> <Editors jsonData={JSON.stringify(jsonData, null, 4)} /> </div> ); }
子组件(接收props中的JSON数据)
import * as React from 'react'; import { useState, useEffect } from 'react'; import YAML from 'yaml'; // 官方YAML包 import { load } from 'js-yaml'; // JavaScript版官方YAML解析包 import Editor from '@monaco-editor/react'; export interface Iprops { jsonData: string; } function Editors(props: Iprops) { const [data, setData] = useState(''); useEffect(() => { setData(props.jsonData); }, [props]); return ( <React.Fragment> <div> <h5>JSON:</h5> <Editor height="300px" defaultLanguage="json" value={data} onChange={(val) => setData(val)} theme="vs-dark" /> </div> <div> <h5>YAML:</h5> <Editor height="300px" defaultLanguage="yaml" value={YAML.stringify(load(data))} // load将JSON字符串解析为普通对象 onChange={(val) => setData(JSON.stringify(load(val), null, 4))} theme="vs-dark" /> </div> </React.Fragment> ); } export default Editors;
需求目标
- 维护统一状态,支持在JSON/YAML编辑器中新增、修改键值对
- 实现JSON与YAML编辑器的实时转换同步
解决方案
原实现的核心问题是将字符串作为状态载体,频繁的JSON/YAML解析转换容易导致状态覆盖或解析失败,进而无法新增键值对。以下是优化后的实现:
修改后的子组件代码
import * as React from 'react'; import { useState, useEffect } from 'react'; import { load, dump } from 'js-yaml'; import Editor from '@monaco-editor/react'; export interface Iprops { jsonData: string; } function Editors(props: Iprops) { // 以JS对象作为核心状态,避免字符串解析的不稳定问题 const [dataObject, setDataObject] = useState<Record<string, any>>({}); // 初始化从props加载并解析数据 useEffect(() => { try { const parsed = JSON.parse(props.jsonData); setDataObject(parsed); } catch (e) { console.error('初始化JSON解析失败:', e); } }, [props.jsonData]); // JSON编辑器变更处理:解析输入并更新核心状态 const handleJsonChange = (val: string | undefined) => { if (!val) return; try { const parsed = JSON.parse(val); setDataObject(parsed); } catch (e) { // 保留错误输入,不重置状态 console.error('JSON解析失败:', e); } }; // YAML编辑器变更处理:解析输入并更新核心状态 const handleYamlChange = (val: string | undefined) => { if (!val) return; try { const parsed = load(val); if (typeof parsed === 'object' && parsed !== null) { setDataObject(parsed); } } catch (e) { // 保留错误输入,不重置状态 console.error('YAML解析失败:', e); } }; return ( <React.Fragment> <div style={{ marginBottom: '20px' }}> <h5>JSON编辑器:</h5> <Editor height="300px" language="json" value={JSON.stringify(dataObject, null, 4)} onChange={handleJsonChange} theme="vs-dark" /> </div> <div> <h5>YAML编辑器:</h5> <Editor height="300px" language="yaml" value={dump(dataObject, { indent: 2 })} onChange={handleYamlChange} theme="vs-dark" /> </div> </React.Fragment> ); } export default Editors;
解决思路说明
- 核心状态用JS对象:避免字符串解析转换带来的错误和状态覆盖问题,所有编辑器的内容都基于该对象生成
- 添加错误捕获:无效输入(如不合法的JSON/YAML)不会重置状态,保留用户输入内容
- 稳定的转换方法:使用
js-yaml的dump方法生成规范YAML,兼容性和可读性更好 - 独立的变更处理:每个编辑器的变更逻辑独立,确保输入内容能正确同步到核心状态
内容的提问来源于stack exchange,提问作者Ram
相关产品推荐
相关产品推荐

