Search code examples
reactjsreact-hooksreact-context

React Hooks createContext: How to update UserContext when its an array?


I have state in my UserContext component:

var initialState = {
  avatar: '/static/uploads/profile-avatars/placeholder.jpg',
  markers: []
};

var UserContext = React.createContext();

function setLocalStorage(key, value) {
  try {
    window.localStorage.setItem(key, JSON.stringify(value));
  } catch (errors) {
    // catch possible errors:
    console.log(errors);
  }
}

function getLocalStorage(key, initialValue) {
  try {
    const value = window.localStorage.getItem(key);
    return value ? JSON.parse(value) : initialValue;
  } catch (e) {
    // if error, return initial value
    return initialValue;
  }
}

function UserProvider({ children }) {
  const [user, setUser] = useState(() => getLocalStorage('user', initialState));
  const [isAvatarUploading, setIsAvatarUploading] = useState(true);

And returning a function to update the array:

  return (
    <UserContext.Provider
      value={{
        userMarkers: user.markers,
        setUserMarkers: markers => setUser({ ...user, markers }),
      }}
    >
      {children}
    </UserContext.Provider>
  );

In my consuming function I am trying to use that function to add an object to the initial array i.e. markers.

export default function MyMap() {
  var { userMarkers, setUserMarkers } = useContext(UserContext);

imagine there is an operation above which changes this value:

setUserMarkers({"id":1,"lat":40.73977053760343,"lng":-73.55357676744462});

What is happening is the old object get completely overridden. so the array gets updated with a new object. Not added. Please help. I also tried concat and it didn't work?

setUserMarkers: markers => setUser(()=> user.markers.concat(markers)),

So markers should be:

  markers: [{"id":0,"lat":40.73977033730345,"lng":-66.55357676744462},{"id":1,"lat":40.73977053760343,"lng":-73.55357676744462}]

Solution

  • Call your function like this to take the previous value and append to it.

    setUserMarkers([...userMarkers, {"id":1,"lat":40.73977053760343,"lng":-73.55357676744462}])
    

    You could also update your function call to always append if you never need to overwrite values in it. Then you can just call it with the new value.

    setUserMarkers: markers => setUser({ ...user, markers: [...user.markers, markers] }),