Spent today figuring out how to load things from localStorage. I would try to declare a variable where variable = JSON.parse(localStorage.getItem("saved")) (where “saved” is an array) or something like that, then use it in my component where I’d map it, but I would get an error stating that there is no such variable.

Server-side rendering v client-side rendering This issue exists due to a difference between server and client-side rendering (Next.js uses server-side rendering). localStorage is available as part of the browser API which only exists on the client’s browser. This is something I don’t entirely understand 1, but I resolved this issue by getting items from localStorage within the useEffect() hook thanks to this article: How to Use localStorage with React Hooks to Set and Get Items.

Updating saved papers from the individual card components

My web app has 2 main components when it comes to showing cards (containing details about papers):

CardContainer.js (Parent)
|
|- Card.js (Child)

CardContainer contains the array of papers from EMNLP’s Excel sheet, and maps each of these papers to a corresponding Card component. It also contains the array of papers that have been saved in localStorage.

However, the act of “saving” occurs when one clicks on the “Save” button in a Card component. Then, how do I update CardContainer’s (parent) state from the Card (child) component?

After checking out bobbyhadz’s “How to pass a Function as props in React”, I passed my CardContainer’s setSaved() function as a prop into the Card component:

CardContainer:

    const [savedPapers, setSaved] = useState([])
    ...
    papers.map(paper => (<Card paper={paper} setSaved={setSaved}/>

Card:

const Card = ({paper, setSaved}) => {
    ...
    function savePaper(){
        setSaved(items => [...items, paper])
    }
    return (
        <> {paper &&  <div className={styles.card}>
        <button onClick={savePaper}>Save</button>
}

I used a spread operator to create a copy of the existing array into a new array where I can add other elements. This works, but I wonder if I should just try passing the entire “Saved” array as a prop and then .push() to it. I used this current solution as I didn’t feel like adding another prop, but that’s not really a technically informed choice…

Progress/Reflections:

Papers can now be saved, but the UI isn’t very user-friendly at the moment as there’s no feedback on when you’re viewing the Saved papers or just browsing the original array of papers. It’s possible to deactivate the “saved” view by clicking “View Saved” again, but it’s not intuitive – I know how to use this because I wrote it, but I don’t think it’d be friendly for people who are using it for the first time.

  • I might want to change the “View Saved” button’s text to “Return to Browsing” when Saved Papers are being shown.

There is also no validation for duplicate saved papers, so it is possible to show multiples of the same paper in the Saved Papers view by clicking one paper’s Save button several times. I should implement validation next.

Also, I think I should use modals for showing abstracts instead of replacing the cards’ contents on click – it’s not a nice viewing experience on desktop (with 2 columns) and isn’t a good utilisation of space as the paper’s abstract is contained within the column that the card is in. This means that only half the viewport’s being used. :\


  1. I roughly know enough about React to make it work, but I don’t think I truly understand things like component lifecycles (render, constructor, componentDidMount etc) or what the difference between client and server-side rendering is. ↩︎