Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How do I pass down components spread props with TypeScript?

EDIT: I focused too much on TypeScript that I didn’t realize I wasn’t mapping the data. It works now.

I am just starting to use TypeScript, and I can’t figure out how to pass down props with the spread operator. How should I do this? from what I understand I shouldn’t be using React.FC so I am trying to do it with interface, but still don’t understand how to get the props. Thank you

Index.tsx:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

    const Home: NextPage = () => {
        const [data, setData] = useState([]);
        console.log(data)
    
        useEffect(() => {
            fetch('https://jsonplaceholder.typicode.com/posts/')
                .then((response) => response.json())
                .then((json) => setData(json));
        }, []);
    
        return (
            <div className={styles.container}>
                <CustomComponent {...data} />
            </div>
        );
    };

export default Home;

CustomComponent.tsx:

    interface Props {
    userId: number;
    id: number;
    title: string;
}

const CustomComponent = ({ userId }: Props) => {
    console.log(userId);
    return <div>{userId}</div>;
};

export default CustomComponent;

>Solution :

You’re trying to use spread on an array (data) in a place where only property spread is supported (the props list of a JSX element expression). Although arrays are objects, their property names are "0" and such, not "userId" and such, so that doesn’t match the props expected by the component.

You’ve said in a comment that you aren’t trying to do anything in particular, just trying to see how to do what you’re doing. Your <CustomComponent {...data}> is just fine if data is an object, but it’s an array.

It looks like your data sorce returns this:

[
    {
        "userId": 1,
        "id": 1,
        "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
        "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
    },
    ...
]

If so, you probably want an array of CustomComponent, and then use ... to spread out each element of data into the props of each CustomComponent.

To do that, you have to set the type of data correctly. Define an interface/object type:

interface PostInfo {
    userId: number;
    id: number;
    title: string;
}

then use an array of those in the setState type arggument so TypeScript knows what’s in the array:

const [data, setData] = useState<PostInfo[]>([]);
//                              ^^^^^^^^^^^^

then render an array of components:

    return (
        <div className={styles.container}>
            {data.map(post => <CustomComponent key={post.id} {...post} />)}
        </div>
    );

Here’s a live example with the TypeScript parts commented out:

const {useState, useEffect} = React;

const styles = {
    container: "container",
};

/*
interface PostInfo {
    userId: number;
    id: number;
    title: string;
}
*/
const Home/*: NextPage*/ = () => {
    const [data, setData] = useState/*<PostInfo[]>*/([]);
    console.log(data)

    useEffect(() => {
        fetch('https://jsonplaceholder.typicode.com/posts/')
            .then((response) => {
                if (!response.ok) {
                    throw new Error(`HTTP error ${response.status}`);
                }
                return response.json();
            })
            .then((data) => setData(data/* as PostInfo[]*/));
    }, []);

    return (
        <div className={styles.container}>
            {data.map(post => <CustomComponent key={post.id} {...post} />)}
        </div>
    );
};

/*
interface Props {
    userId: number;
    id: number;
    title: string;
}
*/

const CustomComponent = ({ userId, id, title }/*: Props*/) => {
    return <div>userId: {userId}, id: {id}, title: {title}</div>;
};

ReactDOM.render(<Home />, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

And the full TypeScript (playground link):

import React, {useState, useEffect} from "react";

// (Stand-in)
const styles = {
    container: "container",
};

interface PostInfo {
    userId: number;
    id: number;
    title: string;
}
const Home/*: NextPage*/ = () => {
    const [data, setData] = useState<PostInfo[]>([]);
    //                              ^^^^^^^^^^^^
    console.log(data)

    useEffect(() => {
        fetch('https://jsonplaceholder.typicode.com/posts/')
            .then((response) => {
                if (!response.ok) {
                    throw new Error(`HTTP error ${response.status}`);
                }
                return response.json();
            })
            .then((data) => setData(data as PostInfo[]));
    }, []);

    return (
        <div className={styles.container}>
            {data.map(post => <CustomComponent {...post} />)}
        </div>
    );
};

interface Props {
    userId: number;
    id: number;
    title: string;
}

const CustomComponent = ({ userId, id, title }: Props) => {
    return <div>userId: {userId}, id: {id}, title: {title}</div>;
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading