我正在尝试将source code组件从类转换为基于函数的组件。这是我第一次这样做,很明显我在这里看不到一些关键因素。
我得到的错误:
MemoryStream
中未定义的“路径”(根据我可以得出的状态。未及时设置选择项或渲染不正确?)这是我到目前为止所拥有的。
JsonPickerPathComp.js:
getRelationship
这是容纳组件的部分。
TlogPathFinderSection.js:
import React, { useState, useEffect} from 'react'
import './style.css'
function JsonPathPickerComp(comp_props) {
console.log("JsonPathPickerComp", comp_props.json);
const [state, setState] = useState({choosen: null});
const [props, setProps] = useState({json: comp_props.json, onChoose: (comp_props.path), path: comp_props.path, showOnly: false});
if (props.json.constructor !== 'String') { // string compare
setState({
choosen: null // reset choosen
})
}
if (props.path !== undefined) {
console.log("props.path !== undefined");
var nextPath;
if (!props.path) { // '' | null
nextPath = props.path
console.log("nextPath = props.path");
} else {
nextPath = props.path.replace(/\./g, ' .')
nextPath = nextPath.replace(/\[/g, ' [')
console.log("nextPath = props.path.replace");
}
setState({
choosen: nextPath
})
}
const choose = (any) => {
console.log("choose running");
let target = any.target
if (target.hasAttribute('data-pathkey')) {
let choosenPath;
console.log("target.hasAttribute: 'data-pathkey' ");
let pathKey = target.getAttribute('data-pathkey')
console.log("pathKey: ", pathKey);
if (target.hasAttribute('data-chooseArr')) {
console.log("target.hasAttribute: 'data-chooseArr' ");
choosenPath = state.choosen
let tmp = choosenPath.split(' ')
let idx = pathKey.split(' ').length
tmp[idx] = '[*]'
choosenPath = tmp.join(' ')
} else {
choosenPath = pathKey
}
setState({
choosen: choosenPath
}, ()=> {
let pathText = state.choosen
pathText = pathText.replace(/ /g, '')
props.onChoose && props.onChoose(pathText)
})
}
}
return (
<div onClick={props.showOnly ? null : choose}>
{ props.showOnly
? json2Jsx_onlyForShow(comp_props.json)
: json2Jsx(state.choosen, comp_props.json, false, state.choosen)}
</div>
)
}
/*
{props.showOnly
? json2Jsx_onlyForShow(jsonObj)
: json2Jsx(state.choosen, jsonObj) }
*/
/**
* recursively generate jsxs by json data
* @param choosenPath
* @param jsonObj
* @param isLast :is the last child or not
* @param pathKey :now json path from root
* @return reactElements
*/
function json2Jsx(choosenPath, jsonObj, isLast, pathKey) {
if (jsonObj === null) {
return renderNull(choosenPath, isLast, pathKey)
} else if (jsonObj === undefined) {
return renderUndefined(choosenPath, isLast, pathKey)
} else if (Array.isArray(jsonObj)) {
return renderArray(choosenPath, isLast, pathKey, jsonObj)
} else if (typeof jsonObj == 'string') {
return renderString(choosenPath, isLast, pathKey, jsonObj)
} else if (typeof jsonObj == 'number') {
return renderNumber(choosenPath, isLast, pathKey, jsonObj)
} else if (typeof jsonObj == 'boolean') {
return renderBoolean(choosenPath, isLast, pathKey, jsonObj)
} else if (typeof jsonObj == 'object') {
return renderObject(choosenPath, isLast, pathKey, jsonObj)
} else {
return null
}
}
/**
* only for show json data
*/
function json2Jsx_onlyForShow(jsonObj, isLast) {
if (jsonObj === null) {
return (
<span className="json-literal">
<span>{'null'} {isLast?'':','}</span>
</span>
)
} else if (jsonObj === undefined) {
return (
<span className="json-literal">
<span>{'undefined'} {isLast?'':','}</span>
</span>
)
} else if (Array.isArray(jsonObj)) {
let arr = jsonObj
let length = arr.length
return (
<div>
<div>
<span>{'['}</span>
</div>
<ol className="json-array">
{
arr.map((value, idx) => {
return (<li key={idx}>
{ json2Jsx_onlyForShow(value, idx == length-1 ? true : false) }
</li>)
})
}
</ol>
<div>{']'} {isLast?'':','}</div>
</div>
)
} else if (typeof jsonObj == 'string') {
let str = escape(jsonObj)
if (isUrl(str)) {
return (
<span>
<a target="_blank" href={str} className="json-literal">
<span>"{str}" {isLast?'':','}</span>
</a>
</span>)
} else {
return (
<span className="json-literal">
<span>"{str}" {isLast?'':','}</span>
</span>)
}
} else if (typeof jsonObj == 'number') {
return (
<span className="json-literal">
<span>{jsonObj} {isLast?'':','}</span>
</span>)
} else if (typeof jsonObj == 'boolean') {
return (
<span className="json-literal">
<span>{jsonObj} {isLast?'':','}</span>
</span>)
} else if (typeof jsonObj == 'object') {
let keys = Object.keys(jsonObj)
let length = keys.length
if (length > 0) {
return (
<div>
<div>
<span>{'{'}</span>
</div>
<ul className="json-dict">
{
keys.map((key, idx) => {
return (<li key={idx}>
<span className="json-literal json-key">{key}</span>
<span> : </span>
{ json2Jsx_onlyForShow(jsonObj[key], idx == length-1 ? true : false) }
</li>)
})
}
</ul>
<div>{'}'} {isLast?'':','}</div>
</div>
)
} else {
return (
<span>
<span>{"{ }"} {isLast?'':','}</span>
</span>)
}
} else {
return null
}
}
/**
* Check if a string represents a valid url
* @return boolean
*/
function isUrl(str){
let regexp = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
return regexp.test(str)
}
function escape(str) {
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
}
/**
* get picker's className, for ditinguishing picked or not or ancestor of picked entity
*/
function getPickerStyle(relation) {
if (relation == 0) {
return "json-pick_path"
} else if (relation == 1) {
return "json-pick_path json-picked"
} else {
return "json-pick_path json-pick_path_ancestor"
}
}
function getPickArrStyle(choosenPath, nowPath) {
let csp = choosenPath.split(' ')
let np = nowPath.split(' ')
if (csp[np.length] == '[*]') {
return "json-pick_arr json-picked_arr"
} else {
return "json-pick_arr"
}
}
// various types' render
function renderNull(choosenPath, isLast, pathKey) {
return (<span className="json-literal">
<i data-pathkey={pathKey} className={getPickerStyle(getRelationship(choosenPath, pathKey))}>?</i>
<span>{'null'} {isLast?'':','}</span>
</span>)
}
function renderUndefined(choosenPath, isLast, pathKey) {
return (<span className="json-literal">
<i data-pathkey={pathKey} className={getPickerStyle(getRelationship(choosenPath, pathKey))}>?</i>
<span>{'undefined'} {isLast?'':','}</span>
</span>)
}
function renderString(choosenPath, isLast, pathKey, str) {
str = escape(str)
if (isUrl(str)) {
return (<span>
<i data-pathkey={pathKey} className={getPickerStyle(getRelationship(choosenPath, pathKey))}>?</i>
<a target="_blank" href={str} className="json-literal">
<span>"{str}" {isLast?'':','}</span>
</a>
</span>)
} else {
return (<span className="json-literal">
<i data-pathkey={pathKey} className={getPickerStyle(getRelationship(choosenPath, pathKey))}>?</i>
<span>"{str}" {isLast?'':','}</span>
</span>)
}
}
function renderNumber(choosenPath, isLast, pathKey, num) {
return (<span className="json-literal">
<i data-pathkey={pathKey} className={getPickerStyle(getRelationship(choosenPath, pathKey))}>?</i>
<span>{num} {isLast?'':','}</span>
</span>)
}
function renderBoolean(choosenPath, isLast, pathKey, bool) {
return (<span className="json-literal">
<i data-pathkey={pathKey} className={getPickerStyle(getRelationship(choosenPath, pathKey))}>?</i>
<span>{bool} {isLast?'':','}</span>
</span>)
}
function renderObject(choosenPath, isLast, pathKey, obj) {
let relation = getRelationship(choosenPath, pathKey)
let keys = Object.keys(obj)
let length = keys.length
if (length > 0) {
return (<div className={relation==1 ? "json-picked_tree" : ''}>
<div>
<span>{'{'}</span>
<i data-pathkey={pathKey} className={getPickerStyle(relation)}>?</i>
</div>
<ul className="json-dict">
{
keys.map((key, idx) => {
let nextPathKey = `${pathKey} .${key}`
return (<li key={nextPathKey}>
<span className="json-literal json-key">{key}</span>
<span> : </span>
{ json2Jsx(choosenPath, obj[key], idx == length-1 ? true : false, nextPathKey) }
</li>)
})
}
</ul>
<div>{'}'} {isLast?'':','}</div>
</div>)
} else {
return (<span>
<i data-pathkey={pathKey} className={getPickerStyle(relation)}>?</i>
<span>{"{ }"} {isLast?'':','}</span>
</span>)
}
}
function renderArray(choosenPath, isLast, pathKey, arr){
let relation = getRelationship(choosenPath, pathKey)
let length = arr.length
if (length > 0) {
return (<div className={relation==1 ? "json-picked_tree" : ''}>
<div>
{ relation==2 ? <i data-pathkey={pathKey} data-chooseArr="1" className={getPickArrStyle(choosenPath, pathKey)}>[✚]</i> : null }
<span>{'['}</span>
<i data-pathkey={pathKey} className={getPickerStyle(relation)}>?</i>
</div>
<ol className="json-array">
{
arr.map((value, idx) => {
let nextPathKey = `${pathKey} [${idx}]`
return (<li key={nextPathKey}>
{ json2Jsx(choosenPath, value, idx == length-1 ? true : false, nextPathKey) }
</li>)
})
}
</ol>
<div>{']'} {isLast?'':','}</div>
</div>)
} else {
return (<span>
<i data-pathkey={pathKey} className={getPickerStyle(relation)}>?</i>
<span>{"[ ]"} {isLast?'':','}</span>
</span>)
}
}
/**
* get the relationship between now path and the choosenPath
* 0 other
* 1 self
* 2 ancestor
*/
function getRelationship(choosenPath, path) {
if (choosenPath === null) return 0
let choosenAttrs = choosenPath.split(' ')
choosenAttrs.shift()
let choosenLen = choosenAttrs.length
let nowAttrs = path.split(' ')
nowAttrs.shift()
let nowLen = nowAttrs.length
if (nowLen > choosenLen) return 0
for (let i=0; i<nowLen; i++) {
let ok
if (nowAttrs[i] === choosenAttrs[i]) {
ok = true
} else if (nowAttrs[i][0] === '[' && choosenAttrs[i][0] === '[' && choosenAttrs[i][1] === '*') {
ok = true
} else {
ok = false
}
if (!ok) return 0
}
return nowLen == choosenLen ? 1 : 2
}
export default React.memo(JsonPathPickerComp);