1

So, I'm having this specific error :

Uncaught Error: Objects are not valid as a React child (found: object with keys {name, component, accessible, is_showed, is_rendered}). 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 Base.

I have a Redux state that looks like the following :

export const initialState = {
    links: [{
        name: 'search_files',
        component: <SearchFile/>,
        accessible: true,
        is_showed: true,
        is_rendered: false
    },
        {
            name: 'invisible_link',
            component: <SearchFile/>,
            accessible: false,
            is_showed: true,
            is_rendered: false
        }
    ],
    user: {
        username: '',
        password: '',
        is_logged: false,
        has_rights: false,
        errors: {
            summary: '',
            username: '',
            password: ''
        }
    },
    panel: {toggled: false}
};

My intent is to render the component pointed by the component property of each link. For the moment, the component is the same for the two links, it's "normal".

The Base component looks like this :

class Base extends React.Component {

    render() {
        let toRender = null;

        if (!this.props.state.user.is_logged)
            toRender = <LoginFormRender/>;
        else
        {
            toRender = this.props.state.links.find(link => {
                if (link.is_rendered) {
                    console.log(link.component);
                    return (link.component);
                }
            })
        }
        return (
            <div>
                <TopBarApp/>
                <LeftPanel/>
                {toRender}
            </div>
        )
    }
}

export default Base;

The LoginFormRender is rendering just good, but the error is here :

else
        {
            toRender = this.props.state.links.find(link => {
                if (link.is_rendered) {
                    console.log(link.component);
                    return (link.component);  <==== HERE
                }
            })
        }

I understand that I visibly can't do it like this (but still, it works storing a component in a var, as LoginFormRender works) but I can't figure out how to achieve this ... Does somebody knows ? I couldn't find any question on SO that answers my question..

Thanks in advance

7
  • 1
    In general case your InitialState should not contain instances of React compontents. Maybe perform some switch by Component/Container name, but InitialState should be serializable. Commented Jul 18, 2017 at 8:37
  • Ah, didn't know that. Thanks for your comment, I'll refactor this ! So if I understand well what you are saying, I can't perform what I want except by doing a switch-case ? Commented Jul 18, 2017 at 8:39
  • You can, but why not keep the raw link entities in state. something like this: toRender = this.props.state.links.find(link => { if (link.is_rendered) { return (<Link {..link} />); } }) You could also improve the business logic by only putting the links to the state, that should be rendered. Commented Jul 18, 2017 at 8:44
  • @larrydahooster I didn't understand what you're trying to do with <Link/>, but the second advice is really interesting, I'll do it if I have the time ! Thanks for taking the time to comment ! Commented Jul 18, 2017 at 8:51
  • 1
    @GaetanBoyals forget about my comment. The answer of Mayank Shukla fixes your probelm. Commented Jul 18, 2017 at 8:58

2 Answers 2

2

Problem is, you are using Array.prototype.find() and it will always return either the value in the array if an element passes the test, otherwise undefined. It will not return the item that you are returning from body.

As per MDN DOC:

The find() method returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.

Check this snippet:

let a = [{a:1}, {a:2}];

let p = a.find(el => {if(el.a > 1) return 10;});

console.log('p = ', p);

Even though i am returning 10, but the value that p will have is {a: 2}.

Solution of your problem:

In your case toRender will have this value after loop:

{
      name: 'invisible_link',
      component: <SearchFile/>,
      accessible: false,
      is_showed: true,
      is_rendered: false
}

That's why it is throwing the error:

Objects are not valid as a React child (found: object with keys {name, component, accessible, is_showed, is_rendered}).

So instead of rendering {toRender} render this:

{toRender.component}

Or write the loop like this:

else{
    this.props.state.links.find(link => {
        if (link.is_rendered) {
            toRender = link.component;
            return 1;
        }
    })
}
Sign up to request clarification or add additional context in comments.

2 Comments

Wow, you nailed it ! Thanks for your answer, it solved the problem ! Still have to take in account the other answers :)
glad, it solved your issue :), yes instead of storing the rendered component, store the string and use conditions to render the component on the basis of string.
1

State is used to have information about current application data structure, but it shouldn't have components in it. You should render components in render() function.

Your render() could look like this

render() {
    return (
        <div>
            <TopBarApp/>
            <LeftPanel/>

            {this.props.state.user.is_logged ? (
                // Render menu links here
                <SearchFile/>
            ) : (
                <LoginFormRender/>
            )}
        </div>
    )
}

1 Comment

As said in the comment of my question, I didn't know that before Vladislav Ihost told me. Still upvoting this for giving me general knowledge. Thanks !

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.