0

I have the following object:

[
  {
    "id": 0,
    "name": "Step 1",
    "summary": "",
    "required": true,
    "articles": [
      {
        "name": "Article 1",
        "url": "...",
        "comments": [],
        "questions": []
      }
    ]
  },
  {
    "id": 1,
    "name": "Step 2",
    "required": true,
    "summary": "",
    "articles": [
      {
        "name": "Article 1",
        "url": "...",
        "comments": [],
        "questions": []
      }
    ]
  },
  {
    "id": 2,
    "name": "Step 3",
    "required": false,
    "summary": "",
    "articles": [
      {
        "name": "Article 1",
        "url": "...",
        "comments": [],
        "questions": []
      },
      {
        "name": "Article 2",
        "url": "...",
        "comments": [],
        "questions": []
      },
      {
        "name": "Article 3",
        "url": "...",
        "comments": [],
        "questions": []
      },
      {
        "name": "Article 4",
        "url": "...",
        "comments": [],
        "questions": []
      }
    ]
  },
  {
    "id": 3,
    "name": "Step 4",
    "summary": "Coming Soon!",
    "required": true
  }
]

There are Steps and each step can have multiple articles.

Folllowing is the Steps component:

import { createElement as ce, Component } from 'react';

class Steps extends Component {

  render() {
    const { steps } = this.props;
    return ce('div', { className:'allTheSteps' }, Step({ steps }));
  };

};

const Step = ({ steps }) => (
  steps.map( ( { name, id, articles }, i ) => ce('div', {className: 'mainBoxes clearfix', key: id},
  ce('strong', {className: 'titleText', key: id + '-' + i}, name),
  ce('div', { className: 'stepArticle'},
    articles.map( ({ name, url }), j ) => Article({ name, url }),
  )
))
);

export default Steps;

Following is the Article component:

import { createElement as ce } from 'react';

const Article = ({ name, url }) => (
    ce('div', {className: 'articleTitle'},
      ce('input', {type: 'checkbox', name: 'done', className: 'checkBoxes'}),
      ce('a', { className: 'checkLink', target: '_blank', href: url }, name),
      ),
    ce('div', {className: 'articleActions'},
      ce('input', {type: 'button', value: 'Make Notes', className: 'addNotes'}),
      ce('input', {type: 'button', value: 'Ask Clausehound', className: 'askQuestions'}),
      ),
    ce('textarea', {className: 'textAreas notes', placeholder: 'My Notes: '}),
    ce('textarea', {
      className: 'textAreas questions',
      placeholder: 'Questions for Clausehound Research Team: ',
    })
);

export default Article;

Following is the index.js which creates the root element:

  const steps = await loadSteps(ID); // fetch
  render(
    ce(Steps, { steps },
      ce(Article, steps.articles)
    ),
    document.querySelector('.root'),
  );

I get the following error:

Uncaught (in promise) Error: Steps.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object

I want to render all the Steps and then the articles within those steps. But the Steps won't render and hence I can't add Articles either.

What is wrong here? I am fairly new to React so I apologize if it is something silly.

1 Answer 1

2

As error itself explain you can't return an array from render method of Steps component. So as a solution you can wrap your array with a div element and then return.

class Steps extends Component {

  render() {
    const { steps } = this.props;
    return ce('div', null, Step({ steps }));
  };

};
Sign up to request clarification or add additional context in comments.

8 Comments

That worked, thanks. Now how do I append the articles to each respective step?
Nm, figured it out. Thanks again. I was always returning an array and not actually creating a React element with those arrays.
It's hard to tell that without knowing what is the exact output you need. But I think you need to put Article component inside the element you create in the map function. Because that's where you can access articles array for each step with something like this steps.map( ( { name, id, articles }, i )...
That was exactly it.
you have put some parenthesis in wrong places. const Step = ({ steps }) => steps.map(({ name, id, articles }, i) => ce( "div", { className: "mainBoxes clearfix", key: id }, ce("strong", { className: "titleText", key: id + "-" + i }, name), ce( "div", { className: "stepArticle" }, articles.map(({ name, url }, j) => Article({ name, url })) ) ) );
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.