【问题标题】:Recursively mapped nested JSON but components do not render递归映射的嵌套 JSON,但组件不呈现
【发布时间】:2021-06-22 22:52:52
【问题描述】:

我递归地映射了嵌套的 JSON,并且控制台日志以 format: property => value 正确输出所有元素,但组件不呈现。以下是 JSON:

{
    "index": "dwarf",
    "name": "Dwarf",
    "speed": 25,
    "ability_bonuses": [
        {
            "ability_score": {
                "index": "con",
                "name": "CON",
                "url": "/api/ability-scores/con"
            },
            "bonus": 2
        }
    ],
    "alignment": "Most dwarves are lawful, believing firmly in the benefits of a well-ordered society. They tend toward good as well, with a strong sense of fair play and a belief that everyone deserves to share in the benefits of a just order.",
    "age": "Dwarves mature at the same rate as humans, but they're considered young until they reach the age of 50. On average, they live about 350 years.",
    "size": "Medium",
    "size_description": "Dwarves stand between 4 and 5 feet tall and average about 150 pounds. Your size is Medium.",
    "starting_proficiencies": [
        {
            "index": "battleaxes",
            "name": "Battleaxes",
            "url": "/api/proficiencies/battleaxes"
        },
        {
            "index": "handaxes",
            "name": "Handaxes",
            "url": "/api/proficiencies/handaxes"
        },
        {
            "index": "light-hammers",
            "name": "Light hammers",
            "url": "/api/proficiencies/light-hammers"
        },
        {
            "index": "warhammers",
            "name": "Warhammers",
            "url": "/api/proficiencies/warhammers"
        }
    ],
    "starting_proficiency_options": {
        "choose": 1,
        "type": "proficiencies",
        "from": [
            {
                "index": "smiths-tools",
                "name": "Smith's tools",
                "url": "/api/proficiencies/smiths-tools"
            },
            {
                "index": "brewers-supplies",
                "name": "Brewer's supplies",
                "url": "/api/proficiencies/brewers-supplies"
            },
            {
                "index": "masons-tools",
                "name": "Mason's tools",
                "url": "/api/proficiencies/masons-tools"
            }
        ]
    },
    "languages": [
        {
            "index": "common",
            "name": "Common",
            "url": "/api/languages/common"
        },
        {
            "index": "dwarvish",
            "name": "Dwarvish",
            "url": "/api/languages/dwarvish"
        }
    ],
    "language_desc": "You can speak, read, and write Common and Dwarvish. Dwarvish is full of hard consonants and guttural sounds, and those characteristics spill over into whatever other language a dwarf might speak.",
    "traits": [
        {
            "index": "darkvision",
            "name": "Darkvision",
            "url": "/api/traits/darkvision"
        },
        {
            "index": "dwarven-resilience",
            "name": "Dwarven Resilience",
            "url": "/api/traits/dwarven-resilience"
        },
        {
            "index": "stonecunning",
            "name": "Stonecunning",
            "url": "/api/traits/stonecunning"
        },
        {
            "index": "dwarven-combat-training",
            "name": "Dwarven Combat Training",
            "url": "/api/traits/dwarven-combat-training"
        },
        {
            "index": "tool-proficiency",
            "name": "Tool Proficiency",
            "url": "/api/traits/tool-proficiency"
        }
    ],
    "subraces": [
        {
            "index": "hill-dwarf",
            "name": "Hill Dwarf",
            "url": "/api/subraces/hill-dwarf"
        }
    ],
    "url": "/api/races/dwarf"
}

那么这是代码:

import React, {Component} from 'react'
import { Grid, Header, Label } from 'semantic-ui-react'

import TypeComponent from './type_component'
import TestComponent from './test_component'

class raceWindow extends Component {
    constructor(props)
    {
        super(props)
        this.state = {
            data: {}
        }
    }

    componentDidMount()
    {
        fetch(this.props.hdAPI)
        .then(response=>response.json())
        .then(data => {this.setState({data: data})});
        this.setState({hdAPI: this.props.hdAPI});
    }

    componentDidUpdate(prevProps)
    {
        if(this.props.hdAPI !== prevProps.hdAPI)
        {
            fetch(this.props.hdAPI)
            .then(response=>response.json())
            .then(data => {this.setState({data: data})});
            this.setState({hdAPI: this.props.hdAPI});
        }
    }

    isType (attr, value)
    {
        if(Array.isArray(value))
        {
            value.map((v) => {
                Object.entries(v).map(([a1,v1]) => this.isType(a1,v1))
            })
        }
        else
        {
        if(typeof value === 'object')
        {
            Object.entries(value).map(([a,v]) => this.isType(a,v))
        }
        else
        {
            console.log(attr);
            console.log(value);
            return(<Grid.Column><Label>{attr}</Label>{value}</Grid.Column>);
        }
        }
    };

    render()
    {
        const { data} = this.state;

        //I also tried to do the recursive map in a component, but it does not work either
        /*
        return(
        <div>
        <Grid container columns = {10}>
        <TypeComponent attr = {""} value = {data} />
        </Grid>
        </div>
        );*/

        return(
        <div>
        <Grid container columns = {10}>
        {this.isType("",data)}
        </Grid>
        </div>
        );
        
    }
}

export default raceWindow

当我尝试在第一层手动映射它时,只渲染了第一层组件。尽管控制台正确输出了更深层的数据,但更深层中的嵌套数据不会呈现。所以我假设反应不会渲染更深的组件。我该如何处理?

编辑:请注意,我可能错了,但我认为isType() 的每个循环最后都会转到这部分代码:

else
      {
            console.log(attr);
            console.log(value);
            return(<Grid.Column><Label>{attr}</Label>{value}</Grid.Column>);
      }

console 也会输出日志中所有非数组、非对象的值,但是这个块中的 return() 不会渲染。

【问题讨论】:

  • 您想要达到的最终结果是什么?一个大问题是您的 isType 函数实际上并没有在前两个 if 块中返回任何内容。你做了某种Object.entries 函数,然后什么也没有发生。也许您想创建一个最终从该函数返回的变量,并将该变量的值设置为等于那些Object.entries 函数的返回值?
  • 我想获取 JSON 中的所有 {property: "some string"} 对。如您所见,有些是嵌套的,即。 '"ability_bonuses"` 是一个数组,"starting_proficiency_options" 是一个对象。我的逻辑是:1.检查它是数组还是对象2.如果是,则获取其中的元素,然后将这些元素一一检查3.如果不是,则必须是字符串或数字,显示在页面
  • 比如我想在页面上显示"index": "con""name": "CON""url": "/api/ability-scores/con""bonus": 2。前3个属于"ability_score""ability_score""bonus": 2都在“ability_bonuses”内。

标签: javascript json reactjs


【解决方案1】:

首先让我们看看你现在遇到的主要问题:

  1. isType 函数中的 if 块不返回任何内容。您正在针对 value 参数运行函数,但是您没有对这些函数返回的内容做任何事情。解决这个问题就像将 value.map... 更改为 value = value.map... 一样简单,但是如果你不做 something,那么当你最后返回时,那些 if 块将没有任何影响关于最终结果。
  2. 在第一个 if 块中,value.map... 函数不会返回任何内容,因为 Object.entries... 周围有括号。你只需要return Object.entries...,或者去掉括号。

如果我们解决这些问题并稍微简化 if/else 逻辑,我们最终会在 JSX 中恢复一些东西:

  isType(attr, value) {
    let returnValue = value;
    if (Array.isArray(returnValue)) {
      returnValue = value.map((v) => {
        return Object.entries(v).map(([a1, v1]) => this.isType(a1, v1));
      });
    } else if (typeof returnValue === "object") {
      returnValue = Object.entries(value).map(([a, v]) => this.isType(a, v));
    }
    return (
      <Grid.Column>
        <Label>{attr}</Label>
        {returnValue}
      </Grid.Column>
    );
  }

但是当你走到这一步时,你会发现生成的 DOM 可能不是你想要的。

相反,我建议稍微改变方法,以便我们首先将我们的 JSON 转换为我们可以使用的结构,然后在我们的渲染函数中映射它。这也有望使您更容易推断何时发生的事情以及修改您的函数以仅将内容添加到您真正关心的最终输出中。

看起来像这样:

class RaceWindow extends Component {
  constructor(props) {
    super(props);

    // your JSON; store in state if necessary
    this.data = {};

    // create a placeholder variable
    this.finalDom = [];

    // call `this.isType` to fill in that variable
    // the result is a giant array of shape {attr: 'str', value: 'str'}
    this.isType("", this.state.data);
  }

  isType(attr, value) {
    if (typeof value === "string") {
      this.finalDom.push({
        attr,
        value
      });
    }
    if (Array.isArray(value)) {
      this.finalDom.push({
        attr,
        value: value.map((v) => {
          return Object.entries(v).map(([a1, v1]) => this.isType(a1, v1));
        })
      });
    }
    if (typeof value === "object") {
      this.finalDom.push({
        attr,
        value: Object.entries(value).map(([a, v]) => this.isType(a, v))
      });
    }
  }

  render() {
    return (
      <div>
        <div class="container">
          {this.finalDom.map((obj) => (
            <div class="item">
              <div class="label">{obj.attr}</div>
              {obj.value}
            </div>
          ))}
        </div>
      </div>
    );
  }
}

CodeSandbox demo of the above.

最后注意:确保组件的第一个字母大写,否则 React 不会将其识别为组件。

【讨论】:

  • 非常感谢,您的回答非常详细且很有帮助。现在我明白了我的概念问题。
【解决方案2】:

以下是工作代码:

import React, {Component} from 'react'
import { Grid, Header, Label } from 'semantic-ui-react'

import TypeComponent from './type_component'
import TestComponent from './test_component'

class raceWindow extends Component {
    constructor(props)
    {
        super(props)
        this.state = {
            data: {}
        }
    }

    componentDidMount()
    {
        fetch(this.props.hdAPI)
        .then(response=>response.json())
        .then(data => {this.setState({data: data})});
        this.setState({hdAPI: this.props.hdAPI});
    }

    componentDidUpdate(prevProps)
    {
        if(this.props.hdAPI !== prevProps.hdAPI)
        {
            fetch(this.props.hdAPI)
            .then(response=>response.json())
            .then(data => {this.setState({data: data})});
            this.setState({hdAPI: this.props.hdAPI});
        }
    }

    isType (attr, value, obj)
    {
        if(Array.isArray(value))
        {
            value.map((v) => {
                Object.entries(v).map(([a1,v1]) => this.isType(a1,v1,obj))
            })
        }
        else
        {
        if(typeof value === 'object')
        {
            Object.entries(value).map(([a,v]) => this.isType(a,v,obj))
        }
        else
        {
            var pair = {}
            pair[attr] = value
            obj.push(pair);
        }
        }
    };

    render()
    {
        const { data} = this.state;
        var obj = [];

        return(
        <div>
        <Grid container columns = {5}>
        {this.isType("",data,obj)}
        {
            obj.map((arr, i) => {
                return(
                    Object.entries(arr).map(([a,v]) => {
                    return(
                        <Grid.Column key = {i}><Label key = {i} color = 'orange'>{a}</Label>{v}</Grid.Column>
                        );
                })
                    );
            })
        }
        </Grid>
        </div>
        );
        
    }
}

export default raceWindow

感谢 cjl750 的建议,我使用一个变量来收集递归函数的结果,它可以工作。我还尝试让非常 if 块有一个返回作为他的建议,但组件仍然不渲染。不知道为什么。

目前看来,递归函数从深层返回的jsx似乎没有渲染。

【讨论】:

  • 看起来您已经非常接近我将要自己发布的内容了,但是由于您仍然遇到一些问题,希望我的回答可以提供帮助。
猜你喜欢
  • 1970-01-01
  • 2016-08-12
  • 1970-01-01
  • 2020-10-25
  • 1970-01-01
  • 2020-02-12
  • 2016-09-24
  • 1970-01-01
  • 2018-03-09
相关资源
最近更新 更多