Jeanmichel Cote
Jeanmichel Cote

Reputation: 531

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

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.

Upvotes: 3

Views: 185

Answers (2)

xyc
xyc

Reputation: 181

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>) }

Upvotes: 1

TimoStaudinger
TimoStaudinger

Reputation: 42460

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
        },
        ...
        ]
    ...    
    }
}

Upvotes: 2

Related Questions