相关文章推荐
害羞的帽子  ·  Java ...·  1 年前    · 
不爱学习的番茄  ·  Python 中 ...·  2 年前    · 
绅士的闹钟  ·  Java8 ...·  2 年前    · 
Cannot read properties of null (reading 'setItem')

Found this error in sentry. The reason is clearly that the localStorage at the time setItem is called is null . The error occurs quite rarely.

Unfortunately, I don't have time to try to reproduce it.

@dbritto-dev I think that is usage issue, so improving docs should help.

This pattern should be something we can recommend in docs.

const myStorage = {
  getItem(name) {
    const value = JSON.parse(localStorage.getItem(name));
    // preferably validate value
    return value;
  setItem(name, value) {
    try {
      localStorage.setItem(name, JSON.stringify(value));
    } catch (e) {
      console.warn(...);
  removeItem(name) {
    localStorage.removeItem(name);
export const useBearStore = create(
  persist(
    (set, get) => ({
      bears: 0,
      inc: () => set((state) => ({ bears: state.bears + 1 })),
    }),
      name: 'bear-storage',
      storage: 

In fact we can do something like this:

const memoryStorage = {
  setItem(name, value) {
    this[`_${name}`] = value
  getItem(name) { 
    return this[`_${name}`]
  removeItem(name) {
    this[`_${name}`] = undefined
const localStorageSupported = () => {
  try { 
    const x = "__storage_test__"
    localStorage.setItem(x, x)
    localStorage.removeItem(x)
    return true
  } catch {
    console.warning(`localStorage is unsupported or unavailable`)
    return false
storage: createJSONStorage(() => {
  if (localStorageSupported()) return localStorage
  return memoryStorage
        

Yes, that's what I was talking about. When using the default implementation, you do not expect that you will still have to handle some edge cases. With such a check, the code will work, even if the localStorage is unavailable for some reason.

And thanks to the warning in the console, users of this middleware will be able to understand what is wrong.

@dbritto-dev I think that is usage issue, so improving docs should help.

This pattern should be something we can recommend in docs.

const myStorage = {
  getItem(name) {
    const value = JSON.parse(localStorage.getItem(name));
    // preferably validate value
    return value;
  setItem(name, value) {
    try {
      localStorage.setItem(name, JSON.stringify(value));
    } catch (e) {
      console.warn(...);
  removeItem(name) {
    localStorage.removeItem(name);
export const useBearStore = create(
  persist(
    (set, get) => ({
      bears: 0,
      inc: () => set((state) => ({ bears: state.bears + 1 })),
    }),
      name: 'bear-storage',
      storage: myStorage
        

Yes, now I agree that this problem should be solved on the side of the middleware user. If you focus on this a little in the documentation, I think there will be no such misunderstanding. And if it does, then you won’t have to spend a lot of time explaining it, but immediately point to the recommendations.

Thanks for the quick help :)

@dbritto-dev Sounds great.

Meanwhile, you could create your own storage without using createJSONStorage to fit with your use case. createJSONStorage isn't designed to cover all cases.

Note again that createJSONStorage isn't ideal, as it relies on JSON.parse which isn't type safe, and there's no validations.
We should consider that createJSONStorage is a fallback mechanism. Preferably, people are encouraged to create their own storage for their needs with type safety and validations.

@dbritto-dev Sounds great.

Meanwhile, you could create your own storage without using createJSONStorage to fit with your use case. createJSONStorage isn't designed to cover all cases.

Note again that createJSONStorage isn't ideal, as it relies on JSON.parse which isn't type safe, and there's no validations.
We should consider that createJSONStorage is a fallback mechanism. Preferably, people are encouraged to create their own storage for their needs with type safety and validations.

@dai-shi yeah, that makes sense.