Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating components through iteration

Something weird is going on:
This is my initial state (a .js file)

import moment       from 'moment';

let date = moment();
var previousDate = moment("2015-12-25");

export const projects = [
      {
        "id": 0,
        "metadata": {
          "fields": 
            [{
              "id":     1,
              "order":  1,
              "name":   "Name",
              "value":  "Collection 1"
            },
            {
              "id":     2,
              "order":  2,
              "name":   "Created On", 
              "value":  date
            },
            {
              "id":     3,
              "order":  3,
              "name":   "Last Modified On", 
              "value":  previousDate
            },
            {
              "id":     4,
              "order":  4,
              "name":   "Status", 
              "value":  "Filed"
            }],

          "tags": 
            [{
              "id":     1,
              "order":  1,
              "value":  "tag1"
            },
            {
              "id":     2,
              "order":  2,
              "value":  "tag2"
            },
            {
              "id":     3,
              "order":  3,
              "value":  "tag3"
            },
            {
              "id":     4,
              "order":  4,
              "value":  "tag4"
            }]   
        }
      }

This is ProjectsList.js:

import React          from 'react';
import Project        from './Project';
import { projects }   from 'initialState';

export default (props) => {
  return(
    <div className="projectsList">
      {projects.map(project => (
        <article key={project.id}><Project fields={project.metadata.fields} /></article>
      ))}
    </div>
  )
}

And this one's Project.js:

import React  from 'react';

export default (props) => {
  return(
    <ul className="fields">
      {props.fields.map(field => <li key={field.id}>{field.name}</li>) }
    </ul>
  )
}

I am trying to render a bunch of projects in a list, and every project contains a bunch of metadata key-value pairs that it shows.

So basically, the wiring does not matter, it all works fine.
Except for this:

If you look up at the initial state file (first one up there), there is an array of multiple objects in fields. Each object shows 4 key-value pairs

  • id
  • order
  • name
  • value

Now, in Project.js, the line where I go

{props.fields.map(field => <li key={field.id}>{field.name}</li>) }

looks like I can switch the {field.name} for {field.id}, to show the id in text. Or I can go {field.order}, to display the order.

But weirdly enough, if I want to show the actual value of the field, like so {field.value}, it throws.

invariant.js?4599:38

Uncaught Invariant Violation: Objects are not valid as a React child (found: Mon Jun 20 2016 21:40:33 GMT-0400). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `StatelessComponent`.   

I even went as far (sigh) as changing the string value in every fields to val, juste to make sure value wasn't some kind of a reserved word.

Still threw.

Anybody can help me understand what I have done wrong, here?
Thanks Guys.

like image 896
Jeanmichel Cote Avatar asked Jul 28 '26 01:07

Jeanmichel Cote


2 Answers

You are assigning to variable values to the value property in your state file, which are most likely not strings, but objects:

export const projects = [{
    "id": 0,
    "metadata": {
      "fields": 
        [
        ...
        {
          "id":     2,
          "order":  2,
          "name":   "Created On", 
          "value":  date                 // one
        },
        {
          "id":     3,
          "order":  3,
          "name":   "Last Modified On", 
          "value":  previousDate         // and another one
        },
        ...
        ]
    ...    
    }
}
like image 83
TimoStaudinger Avatar answered Jul 30 '26 15:07

TimoStaudinger


If typeof children returns "object" (and children is neither an array, nor a ReactElement), it throws: https://github.com/facebook/react/blob/dc6fc8cc0726458a14f0544a30514af208d0098b/src/shared/utils/traverseAllChildren.js#L169

Here's a simplest example to demonstrate this:

const IllegalComponent = () => <span>{{}}</span>

You are supposed to supply a string (or number) so that React could inline that as the children in <li>. Children should be something that's renderable and implements ReactNode.

If the children is an object, React would not know how to render it. You should explicitly convert the value to String.

Try this to see if it works:

{props.fields.map(field => <li key={field.id}>{field.value.toString()}</li>) }
like image 28
xyc Avatar answered Jul 30 '26 14:07

xyc



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!