5

A developer gave me an api specification which is a List that can accept an array of objects using the ListItem shape described below; this will be transformed into a set of rendered List.Item components.

API

The List component accepts the following props:

  • items (ListItem[]): Required. This array should contain one or more JSX elements, or one or more ListItem objects (see below for details).
  • searchable (string[]): Optional. Accepts an array of strings which match the names of ListItem properties. If present, a localized freeform search box is rendered above the list, and entry within that field will filter the internal data using the provided keys as a guide.

Schemas


ListItem

ListItem is the object schema for an individual item in the list.

{
    // REQUIRED: The main title of the list item.
    title: string,
    // OPTIONAL: A secondary title.
    subtitle: string,
    // OPTIONAL: Additional labeling which appears directly below the title or subtitle label: String,
    // OPTIONAL: If provided, a date will always appear at the top of the list item
    date: Date,
    // OPTIONAL: An array of actions which are appended to the right side of the list item.
    actions: [
        {
            label: string | JSX.Element,
            action: Function
        }
    ]
}


My implementation which is not working

journalList.jsx

import PropTypes from "prop-types";
import React from "react";
import {Components} from "reusable-web-components";

const {
    Icon,
    List
} = Components;

const JournalList = (props) => {
  const {description, title} = props;
  
  const formattedItems = [
    {
        title: title,
        description: description,
        actions: [
            {
                label: <Icon name="edit" />,
                action: () => {}
            },
            {
                label: <Icon name="delete" />,
                action: () => {}
            }
        ]
    }
];
    return(
        <List items={formattedItems} searchable={["title"]} />
    )
}

JournalList.propTypes = {
  "title": PropTypes.string.isRequired,
  "description": PropTypes.string.isRequired
};

JournalList.defaultProps = {
    
};

export default JournalList;


Now here is the parent component

journal.jsx

import api from "bees";
import JournalList from './JournalList';
import React from "react";
import store from "store";


class Journal extends React.Component {
    constructor (props) {
        super(props)
        this.state = {
            "displayList": true,
            "journalList": null,
            "searchJournalList": []
        }
    }

    componentDidMount = () => {
        store.dispatch(api.getJournals()).then((result) => {
            this.setState(() => ({"journalList": result.body.data}));
        }).
            catch(() => {
                this.setState(() => ({"journalList": []}));
            });
    }

    onEdit = () => {
        // TODO: Update a Journal
    }

    onDelete = () => {
        // TODO: Delete a Journal 
    }
    render() {
        return (
            <div>
               
                    <JournalList>
                        {
                            journalList.map((items) => {
                                return{
                                    key={items.title}
                                        title={items.title} 
                                        description={items.description} 
                                }
                            })                            
                        }
                    </JournalList>
               
            </div>            
        ) 
    }   
}


export default Journal;

I need to be able to successfully iterate over the data I am getting from my store and create a list of journal entries. According to his documentation the output should look like this:

<div>
  <div class="list">
    <div class="list__search">
      <div class="form-group">
        <input placeholder="Search" id="ListSearch_0.1429790340540955" class="form-control">
      </div>
    </div>
    <div class="list__item">
      <div class="list-item">
        <div class="list-item__contents">
          <div class="list-item-contents">
            <div class="list-item-contents__title">Journal 1</div>
            <div class="list-item-contents__title">Journal 2</div>
          </div>
        </div>
        <div class="list-item__actions">
          <button class="list-item-action"><svg class="icon icon--medium"><use xlink: href="#edit-icon"></use></svg></button>
          <button class="list-item-action"><svg class="icon icon--medium"><use xlink: href="#delete-icon"></use></svg></button>
        </div>
      </div>
    </div>
  </div>
</div>

0

1 Answer 1

2

The render method of your Journal component should be like:

render() {
    return (
        <div>
            {this.state.journalList.map((items) => {
                <JournalList key={items.title}
                             title={items.title} 
                             description={items.description}>
                </JournalList>
                       })                            
            }
        </div>            
    ) 
} 

And change the state declaration to:

this.state = {
        displayList: true,
        journalList: [],
        searchJournalList: []
    }

You've reversed the order of the things. The map() should wrap the component <JournalList>, instead of the <JournalList> wrap the journalList.map(). Because the map will iterate through the journalList and create each component.

EDIT:

Your JournalList component is "unuseful". It is creating multiple lists, but you only needs one. Change your <JournalList> to this:

import PropTypes from "prop-types";
import React from "react";
import {Components} from "reusable-web-components";
import store from "store"

const {
    Icon,
    List
} = Components;

const JournalList = (props) => {
    state = {
       journalList: []
    }
    componentDidMount = () => {
        store.dispatch(api.getJournals()).then((result) => {
            var formattedItems = result.body.data.map( data => {
              title: data.title,
              description: data.description,
                 actions: [
                    {
                       label: <Icon name="edit" />,
                       action: () => {}
                    },
                    {
                       label: <Icon name="delete" />,
                       action: () => {}
                    }
                 ] 
              }) // End of the map
            this.setState(() => ({"journalList": formattedItems}));
        }).
            catch(() => {
                this.setState(() => ({"journalList": []}));
            });
    }
    render(){
       return(
          <List items={this.state.journalList} searchable={["title"]} />
       )
    }
}

export default JournalList;

Doing this, you JournalList component will be useful, and you won't need the <Journal> Component.

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

9 Comments

I am getting an error Uncaught TypeError: Cannot read property 'map' of null
Are you sure journalList.jsx is the file and not journal.jsx because I am still getting the error.
render() { const {displayForm, displayList, journalList} = this.state; return ( <div> {journalList.map((items) => { return( <JournalList key={items.title} title={items.title} description={items.description} /> ) }) }
I am still getting the Uncaught TypeError: Cannot read property 'map' of null
Even though I am now seeing everything work. I am getting a separate list for every item.
|

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.