Home > front end >  Store number using localStorage with custom hook React
Store number using localStorage with custom hook React

Time:12-05

I'm trying to store a number for a counter that initializes as 0 and counts up 1 every time a user uploads a photo. Im getting undefined in Profile console.log orderHook.orderCount. In localStorage i get console.log of {count:0}
Any help is greatly appreciated!

LocalStorage.js:

import { useState, useEffect } from 'react';

function getStorageValue(key, defaultValue) {
    // getting stored value
    const saved = localStorage.getItem(key);
    const initial = JSON.parse(saved); // unexpected character @ line 1 column 1 
    // const initial = JSON.stringify(saved); 
    return initial || defaultValue;
}

export const useLocalStorage = (key, defaultValue) => {
    const [value, setValue] = useState(() => {
        console.log(key)
        return getStorageValue(key, defaultValue);
    });

    useEffect(() => {
        localStorage.setItem(key, JSON.stringify(value));
    }, [key, value]);

    return [value, setValue];
};

Count.js: custom hook

import { useLocalStorage } from "../../Utilities/localStorage/localStorage"; // Local storage hook

function useOrderCountHook() {
    const [orderCount, setOrderCount] = useLocalStorage({count: 0}); // The profile image

    const changeOrderCount = () => {
        setOrderCount({ count: orderCount.count   1 })
    }
    return { orderCount, changeOrderCount };
    // return [orderCount, changeOrderCount];
}

export default useOrderCountHook;

Profile.js: using customhook

    const orderHook = useOrderCountHook(); // How the photo count hook is called

    console.log(typeof (orderHook.orderCount)) // undefined
    console.log(orderHook.orderCount) // undefined

    const handleUploadChange = e => { // Input onChange 
        if (e.target.files[0]) {
            setImage(e.target.files[0]);
        } else { }
        return handleCountChange()
    };

    const handleCountChange = () => { // Function for custom count hook
        if (orderHook.orderCount === undefined) {
            return 
        } else {
            return orderHook.orderCount
        }
    }
      return (
                        {
                            currentUser ?
                                <input
                                    type="file"
                                    for="Upload Image"
                                    accept="image/*"
                                    name="image"
                                    id="file"
                                    onChange={handleUploadChange}
                                    onClick={handleUploadChange}
                                    style={{ display: "none" }}
                                />
                                : ''
                           }

                        <i className="bi bi-camera">      
                            {orderHook.orderCount === undefined ?
                                <span className="banner-list-font mx-1">0 photos</span>
                                :
                                <span className="banner-list-font mx-1">{orderHook.orderCount.count} photos</span>
                            }
                        </i>

**UPDATE**
So i managed to get it working but when i signed the user out and signed back in now if i try to upload a photo i get the error Cannot read properties of undefined (reading 'count'). which is the defaultValue prop and that console logs as undefined. I think the problem is that count is being stored as an object ?

localStorage.js:

import { useState, useEffect } from 'react';

// function getStorageValue(key, defaultValue) {
//     const saved = localStorage.getItem(key);
//     console.log(saved, defaultValue, key)// => null undefined {count:0}
//     const initial = JSON.parse(saved);
//     console.log(initial)
//     // const initial = JSON.stringify(saved); 
//     // return key || defaultValue;
//     return initial || defaultValue;
// }

function getStorageValue(key, defaultValue) {
    const saved = localStorage.getItem(key);
    console.log(saved, defaultValue, key)// => null undefined {count:0}
    if (saved === null) {
        return defaultValue;
    }
    return JSON.parse(saved);
}

export const useLocalStorage = (key, defaultValue) => {
    console.log(key, defaultValue)// => {count:0} undefined
    const [value, setValue] = useState(() => {
        return getStorageValue(key, defaultValue);
    });

    useEffect(() => {
        localStorage.setItem(key, JSON.stringify(value));
    }, [key, value]);

    return [value, setValue];
};

Profile.js:
return (
<input
      type="file"
      for="Upload Image"
      accept="image/*"
      name="image"
      id="file"
      onChange={e => { orderHook.changeOrderCount(e); handleUploadChange(e) }}
      onClick={handleUploadChange}
      style={{ display: "none" }}
     />

 <i className="bi bi-camera"></i>                              
    {orderHook.orderCount === undefined || orderHook.orderCount === null ?
     <span className="banner-list-font mx-1">0 photos</span> 
     :
     <span className="banner-list-font mx-1">{orderHook.orderCount.count} photos</span>
     }

CodePudding user response:

It looks like the error comes from your getStorageValue function, here is a fixed implementation:

function getStorageValue(key, defaultValue) {
  const saved = localStorage.getItem(key);
  if (saved === null) {
    return defaultValue;
  }
  return JSON.parse(saved);
}

I would recommend using a library instead of writing your own implementation of useLocalStorage. Check out the useStorage hook from the react-tidy library.

Disclaimer I am the author of that library.

CodePudding user response:

Instead of:

    const [orderCount, setOrderCount] = useLocalStorage({count: 0}); // The profile image

you should use:

    const [orderCount, setOrderCount] = useLocalStorage("count", 0); // The profile image

CodePudding user response:

Well i've been testing this for about 15 minutes and i cant get it to break so i think its working....then again i thought this feature was already working a week ago. Heres what i came up with.
LocalStorage.js:

import { useState, useEffect } from 'react';

function getStorageValue(key, defaultValue) {
    const saved = localStorage.getItem(key);
    console.log(saved, defaultValue, key)
    const initial = JSON.parse(saved); // unexpected character @ line 1 column 1 
    console.log(initial)
    if (initial === null || initial === undefined) {
        return key
    } else {
        return initial
    }
}

export const useLocalStorage = (key, defaultValue) => {
    console.log(key, defaultValue)
    const [value, setValue] = useState(() => {
        return getStorageValue(key, defaultValue);
    });

    useEffect(() => {
        localStorage.setItem(key, JSON.stringify(value));
    }, [key, value]);

    return [value, setValue];
};

Count.js:

import { useLocalStorage } from "../../Utilities/localStorage/localStorage"; // Local storage hook

function useOrderCountHook() {
    const [orderCount, setOrderCount] = useLocalStorage({count: 0}); // The profile image

    const changeOrderCount = () => {
        setOrderCount({ count: orderCount.count   1 })
    }
    
    return { orderCount, changeOrderCount };
}

export default useOrderCountHook;

Profile.js:

const orderHook = useOrderCountHook(); // Photo count hook
                {
                    currentUser ?
                        <input
                            type="file"
                            for="Upload Image"
                            accept="image/*"
                            name="image"
                            id="file"
                            onChange={e => { orderHook.changeOrderCount(e); handleUploadChange(e) }}
                            onClick={handleUploadChange}
                            style={{ display: "none" }}
                        />
                        : ''
                }

                 <div className="">
                    <i className="bi bi-camera"></i>                              
                    {orderHook.orderCount === undefined || orderHook.orderCount === null ?
                    <span className="banner-list-font mx-1">0 photos</span> 
                     :
                     <span className="banner-list-font mx-1">{orderHook.orderCount.count} photos</span>                    
                  </div>
  • Related