将React类组件转换为功能组件时遇到麻烦

时间:2020-05-08 08:19:15

标签: reactjs

我正在尝试将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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
}

/**
 * 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);

0 个答案:

没有答案