Ian Vink
Ian Vink

Reputation: 68830

ReactJS: Typescript .map is not a function

ReactJS Newbie question

In this typescript example, I get the error that this.state.map is not a function, but the props is set to an array??

class App extends React.Component<IProfile[],any>  {

constructor(props:IProfile[]) {
    super(props);
    this.state = { profiles: props };
    console.log(this.state);
}

public render() {

    return (<div>
                {this.state.profiles.map((profile: IProfile) => <Card {...profile} />)}
            </div>);
}

};

I call it with this:

ReactDOM.render(
   <App {...testData}/>,
    document.getElementById("root")
);

where:

const testData = [
{ name: "Dan Abramov", avatar_url: 
    "https://avatars0.githubusercontent.com/u/810438?v=4", company: "@facebook" },

   ];

Upvotes: 0

Views: 979

Answers (1)

tylerwgrass
tylerwgrass

Reputation: 656

this.state is an object of which you assign fields to. Your constructor should look more like this:

constructor(props) {
    super(props);
    this.state = {
        profiles: props.profiles
    };
}

and then you can map like this:

return (
    <div style={{ background: 'green', width: 50 }}>
        {this.state.profiles.map((profile: IProfile) => <Card {...profile} />)}
    </div>
);

When passing data into your component you have a couple options:

Passing a named variable

This can be used when you only want to pass a few props from the parent component to the child component.

In your example, if you want to pass testData down into the App component to appear as profiles in App component's props, you would do this:

const testData = [
    { name: "Dan Abramov", 
    avatar_url: "https://avatars0.githubusercontent.com/u/810438?v=4", 
    company: "@facebook" 
  },
];

ReactDOM.render(
   <App profiles={testData}/>,
    document.getElementById("root")
);

This will provide testData as this.props.profiles in the App component.

Passing multiple fields at once

Say you have multiple fields you want to pass, stored in an object like so:

testData = {
    profiles: [...],
    createdAt: ...,
    isValid: true
}

You can pass all this data at once using this syntax:

ReactDOM.render(
   <App {...testData}/>,
    document.getElementById("root")
);

This will provide access to all the fields in the child component with the names they have in the original object like so:

constructor(props) {
    super(props);
    console.log(this.props);
    /* This will print:
        { profiles: [...], isValid: true, createdAt: ... }
    */
}

You can also combine both of them to pass some named data, as well as the rest as props. This is common in Higher Order Components.

Here is a working fiddle for you to look at.

Upvotes: 2

Related Questions