Expansion state is lost when src prop updates to an object missing a previously expanded path.
Description:
The component's internal expansion state is destructively modified when the src prop is updated. If a previously expanded path does not exist in the new src object, that path is permanently removed from the expansion state. This causes a poor user experience when navigating between objects that have slightly different data structures, as the user's manual expansions are lost.
Steps to Reproduce:
- Render the
JsonView component with an initial src object, for example:
{ "request": { "header": { "id": "123" } }, "other_data": {} }
- Manually expand the
request node, and then expand the nested header node.
- Update the component by passing a new
src prop that is missing the header node, for example:
{ "request": { "body": { "id": "456" } }, "other_data": {} }
- Update the component again by passing the original
src prop from step 1.
Actual Behavior:
In step 4, the header node is rendered as collapsed. The user's interaction state from step 2 has been lost.
Expected Behavior:
The component's internal expansion state should be preserved across src updates. In step 4, the header node should be rendered as expanded, just as the user left it in step 2. The absence of a path in one src object should not purge that path's state for subsequent re-renders.
Suggested Fix / Architectural Analysis:
The root cause of this issue is the decentralized state management for collapsed nodes.
In src/components/object-node.tsx, the collapse state for each individual object/array is managed by a local useState hook:
// in src/components/object-node.tsx
const [fold, _setFold] = useState(isCollapsed(...))
Because this state is local to each ObjectNode instance, it is destroyed when that component unmounts. When the src prop of the main JsonView component is updated with an object that has a different structure, the old component instances are unmounted, and their local state is permanently lost.
A more robust architectural solution would be to centralize the expansion state.
The expansion state for the entire tree could be managed within the top-level JsonView component (src/components/json-view.tsx). This could be a single state object that maps node paths to their collapsed status (e.g., collapsedPaths: { 'request.header': false }).
Expansion state is lost when
srcprop updates to an object missing a previously expanded path.Description:
The component's internal expansion state is destructively modified when the
srcprop is updated. If a previously expanded path does not exist in the newsrcobject, that path is permanently removed from the expansion state. This causes a poor user experience when navigating between objects that have slightly different data structures, as the user's manual expansions are lost.Steps to Reproduce:
JsonViewcomponent with an initialsrcobject, for example:{ "request": { "header": { "id": "123" } }, "other_data": {} }requestnode, and then expand the nestedheadernode.srcprop that is missing theheadernode, for example:{ "request": { "body": { "id": "456" } }, "other_data": {} }srcprop from step 1.Actual Behavior:
In step 4, the
headernode is rendered as collapsed. The user's interaction state from step 2 has been lost.Expected Behavior:
The component's internal expansion state should be preserved across
srcupdates. In step 4, theheadernode should be rendered as expanded, just as the user left it in step 2. The absence of a path in onesrcobject should not purge that path's state for subsequent re-renders.Suggested Fix / Architectural Analysis:
The root cause of this issue is the decentralized state management for collapsed nodes.
In
src/components/object-node.tsx, the collapse state for each individual object/array is managed by a localuseStatehook:Because this state is local to each
ObjectNodeinstance, it is destroyed when that component unmounts. When thesrcprop of the mainJsonViewcomponent is updated with an object that has a different structure, the old component instances are unmounted, and their local state is permanently lost.A more robust architectural solution would be to centralize the expansion state.
The expansion state for the entire tree could be managed within the top-level
JsonViewcomponent (src/components/json-view.tsx). This could be a single state object that maps node paths to their collapsed status (e.g.,collapsedPaths: { 'request.header': false }).