0

For a react project that I am building, I have a context provider which gives the user a link to a composition based on the parameters they selected. I want this state(the compositions) to be saved, and have tried local storage, however my state is not persisting after a refresh.

Here is the code for my context provider

import {createContext, useContext, useState, useEffect} from 'react';
import { storage } from '../../../Config/firebaseConfig';
import {ref, deleteObject} from 'firebase/storage'

 const CompositionsContext = createContext(['There are no Compositions']);

 const useCompositions = () => useContext(CompositionsContext);

 const CompositionContextProvider = ({children}) => {
    const[compositions, setCompositions] = useState([]);

    useEffect(() => {
        const storedState = localStorage.getItem('compositions');
        if (storedState) {
          setCompositions(JSON.parse(storedState));
        }
      }, []);
    
      useEffect(() => {
        localStorage.setItem('compositions', JSON.stringify(compositions));
      }, [compositions]);

    const addNewComposition = (newComposition) => {
        setCompositions(compositions => compositions.concat(newComposition));
    }

    const deleteComposition = (indexValue) => {
        setCompositions(compositions => compositions.filter((_,index) => index !== indexValue))
        const storageRef = ref(storage, `pdfs/${compositions[indexValue ]}.pdf`)
        deleteObject(storageRef);
    }


    return (
        <CompositionsContext.Provider value={{addNewComposition, compositions, deleteComposition}}>
            {children}
        </CompositionsContext.Provider>
    )
 }

 export {useCompositions};
 export default CompositionContextProvider;

And here are the components in which the ContextProvider is being used.

import React, { useState } from 'react';
import { useCompositions } from './Contexts/CompositionContextProvider';


const CreateComposition = () =>{
    const {addNewComposition} = useCompositions();
    const [taal, setTaal] = useState('');
    const [bpm, setBpm] = useState('');
    const [name, setName] = useState('');

    const options = [
      {label : "", value: ""},
      {label: "Teentaal", value: "Teentaal"},
      {label: "Jhaptaal", value: "Jhaptaal"},
      {label: "Ektaal", value: "Ektaal"},
      {label: "Rupak", value: "Rupak"}
    ]
  
    const sayKayeda = () => {
      alert(taal + " " + bpm + " " + name);
    }
  
    const changeTaal = (event) => {
      setTaal(event.target.value);
    }
  
    const changeBPM = (event) => {
      setBpm(event.target.value);
    }
  
    const changeName = (event) => {
      setName(event.target.value);
    }

  
    const addNewCompositionHandler = () => {
      const newComposition = `${taal}_${bpm}_${name}`;
      addNewComposition(newComposition)
      setTaal('');
      setBpm('');
      setName('');
      
    }


    return (
    <>
        <h2>Input Kayeda Details Below</h2>
        <br></br>
        <br></br>
        <label> <b>Select a Taal</b>&nbsp; 
          {/* <input onChange={changeTaal} value={taal}></input> */}
          <select onChange = {changeTaal}>
            {options.map(option =>(
              <option value={option.value}>{option.label}</option>
            ))}
          </select>
        </label>
        <p></p>
        <label> <b>BPM</b>&nbsp; 
            <input onChange={changeBPM} value={bpm}></input>
        </label>
        <p></p>
        <label> <b>Name</b>&nbsp; 
            <input onChange={changeName} value={name}></input>
        </label>
        <p></p>
        <button onClick={sayKayeda}>Current Kayeda</button>
        &nbsp; 
        <button onClick={addNewCompositionHandler}>Add Composition</button>
        <p></p>
    </>
    );
}


export default CreateComposition;

Here is the second component

// Compositions.js
import React, { useEffect, useState } from 'react';
import { useCompositions } from './Contexts/CompositionContextProvider';
import TeentaalPDF from '../../PDFs/TeentaalE.pdf';
import JhaptaalPDF from '../../PDFs/JhaptaalE.pdf';
import EktaalPDF from '../../PDFs/EktaalE.pdf';
import RupakPDF from '../../PDFs/RupakE.pdf';
import { storage } from '../../Config/firebaseConfig';
import { ref, getDownloadURL, uploadBytes} from 'firebase/storage';

const Compositions = () => {
  const {compositions, deleteComposition} = useCompositions();
  const [pdfLinks, setPdfLinks] = useState({});
  const [fileUpload, setFileUpload] = useState(null);

  useEffect(() => {
    const fetchPDFLinks = async () => {
      const links = {};
      for (const composition of compositions) {
        const downloadURL = await getPDFDownloadURLFromStorage(composition);
        links[composition] = downloadURL || getDefaultPDF(composition);
      }
      setPdfLinks(links);
    };

    fetchPDFLinks();
  }, [compositions]);

  const getPDFDownloadURLFromStorage = async (composition) => {
    const storageRef = ref(storage, `pdfs/${composition}.pdf`);
    try {
      const downloadURL = await getDownloadURL(storageRef);
      return downloadURL;
    } catch (error) {
      console.error(error);
      return null
    }
  };

  const getDefaultPDF = (composition) => {
    if (composition.includes('Teentaal')) {
      return TeentaalPDF;
    } else if (composition.includes('Jhaptaal')) {
      return JhaptaalPDF;
    } else if (composition.includes('Ektaal')) {
      return EktaalPDF;
    } else if (composition.includes('Rupak')) {
      return RupakPDF;
    } else {
      return null; // Return null or a default PDF for unmatched compositions
    }
  };

  const onSubmitComposition = async (newCompositionName) => {
    if(!fileUpload) return;
    const storageRef = ref(storage, `pdfs/${newCompositionName}.pdf`);
    try {
      await uploadBytes(storageRef, fileUpload); // Uploading file to Firebase Storage

    } catch (error) {
      console.error('Error uploading file:', error);
    }
  };

  return (
    <>
      <h2>List of Compositions</h2>
      <h2>{compositions.length}</h2>
      <ul>
        {compositions.map((composition, index) => (
          <li key={index}>
            <a href={pdfLinks[composition]} target="_blank" rel="noreferrer">{composition} </a> &nbsp;
            <button onClick={() => deleteComposition(index)}>Delete Composition</button>
            <p>
              <input type = "file" onChange={(e) => setFileUpload(e.target.files[0])}/>
              <button onClick={() => onSubmitComposition(composition)}>
                Store Composition
              </button>
            </p>
          </li>
        ))}
      </ul>
    </>
  );
};

export default Compositions;
3
  • 1
    Can you see it being saved into local storage in devtools? It looks like your second hook will be overriding the record in local storage with [] when it mounts again. Commented Dec 14, 2023 at 17:10
  • I tried it with both run build and start, and it seems to work on run build but not start command. Is there a reason for that? Commented Dec 14, 2023 at 22:00
  • @51014 What do you mean by it works on run build? How did you check it run on build? Commented Dec 15, 2023 at 8:48

0

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.