Как предотвратить использование LocalStorage с помощью команды redux-persist до того, как оно будет разрешено пользователем? - PullRequest
7 голосов
/ 13 апреля 2020

Я бы хотел получить согласие пользователя, нажав на кнопку баннера, прежде чем использовать LocalStorage. LocalStorage используется через redux-persist. Я использую redux и redux-persist следующим образом:

ReactDOM.render(
  <Provider store={store}>
    <PersistGate loading={null} persistor={persitor} >
      <MyAppRouter />
    </PersistGate>
  </Provider>,
  document.getElementById("root")
)

и store и persistor поступают из

import { createStore } from "redux"
import { persistStore, persistReducer } from "redux-persist"
import storage from "redux-persist/lib/storage"
import { rootReducer } from "../reducers/index"

const persistConfig = {
  key: "root",
  storage,
}

const persistedReducer = persistReducer(persistConfig, rootReducer)

const store = createStore(persistedReducer)
const persistor = persistStore(store as any)
// `as any` is necessary as long as https://github.com/reduxjs/redux/issues/2709 is not fixed

export { store, persistor }

redux-persist сохраняется начальное состояние в LocalStorage, как только объекты создаются, что не то, что я хочу.

Я хотел бы использовать избыточность в моих компонентах React независимо от того, сохраняется ли состояние или нет.

I Предположим, что детали редуктора не имеют значения, поскольку они не влияют на то, где и как хранится состояние.

Информация, которую пользователь однажды выразил согласие на использование LocalStorage и файлов cookie, хранится в cook ie.

Как я могу начать использовать LocalStorage для настойчивости только после того, как пользователь выразил согласие во время первого посещения, или если повар ie уже присутствует? Случай, когда повар ie истек или был удален, должен охватываться случаем первого визита.

Чтобы минимизировать обсуждение, я ищу решение, которое решает техническую проблему. Запрос может быть излишним с точки зрения требований законодательства.

То, что я пробовал до сих пор:

  • Использование двух хранилищ (вероятно, плохой практики), которые управляются в состоянии App компонент, который упаковывает Provider, как показано в примере. Проблема заключается в том, что страница перерисовывается после нажатия кнопки баннера, что недопустимо.
  • Оценивается черный список, который не будет работать, поскольку он не влияет на первоначальное сохранение состояния.

[1] https://softwareengineering.stackexchange.com/questions/290566/is-localstorage-under-the-cookie-law

1 Ответ

6 голосов
/ 18 апреля 2020

Идея заключается в том, что персисторная составляющая резерв-перенаправителя отвечает за сохранение данных или состояния редукции в localStorage.

Чтобы принять решение на основе согласия пользователя, вам необходимо условно отобразить или нет компонент PersistGate

. Чтобы решить такую ​​проблему, вы можете написать собственный компонент поверх Persistor, который оказывает его только тогда, когда разрешение предоставлено. Кроме того, logi c, чтобы побудить пользователя предоставить или отклонить разрешение, может go в том же компоненте

Пример

class PermissionAndPersist extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
        permission: this.getCookie('userLocalStoragePermission')
    }
  }

  getCookie(name) {
    //implement the getc ookie method using document.cookie or a library

    /* state returned must have the following syntax
         isPermissionGranted,
         isCookieExpired
    */ 

    // The above syntax can be determined based on whether cookie is present as well as by checking the expiry data if cookie was present
  }

  render() {
      const { permission } = this.state;
      const {children, persistor} = this.props;
      if(!permission.isPermissionGranted) {
         // no permission granted, return a plain div/Fragment
         return (
            <React.Fragment>
              {children}
            </React.Fragment>
         )
      }
      if(permission.isCookieExpired) {
          return <Modal>{/* here goes a component which asks for user permission and on click updates the state as well as update in cookie */}</Modal>
      }
      // now if the cookie is present and permission is granted and cookie is not expired you render the `PersistGate` component
      return <PersistGate persistor={persitor} >{children}</PersistGate> 
  }
}

Как только вы создадите компонент, как указано выше, вы будете рендерить его следующим образом

ReactDOM.render(
  <Provider store={store}>
    <PermissionAndPersist persistor={persitor} >
      <MyAppRouter />
    </PermissionAndPersist >
  </Provider>,
  document.getElementById("root")
)

Примечание: Вы всегда можете изменить реализацию компонента PermissionAndPersist в зависимости от требований, но учтите, что PeristGate должен отображаться только тогда, когда все условия совпадают. Также вы можете захотеть очистить localStorage, если пользователь не предоставляет разрешения

РЕДАКТИРОВАТЬ: Поскольку требуется фактически не повторять рендеринг всего приложения при нажатии на баннер пользователя, нам нужно внести несколько изменений.

Во-первых, повторно выполните рендеринг ModalComponent на основе условия. Во-вторых, мы не можем условно изменить компонент, который мы перерисовываем, иначе все приложение обновляется. Единственный способ добиться этого на данный момент - это на самом деле реализовать logi c для сохранения состояния избыточности в localStorage самостоятельно и получить его изначально при refre sh

class PermissionAndPersist extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
            permission: this.getCookie('userLocalStoragePermission')
        }
      }

      getCookie(name) {
        //implement the getc ookie method using document.cookie or a library

        /* state returned must have the following syntax
             isPermissionGranted,
             isCookieExpired
        */ 

        // The above syntax can be determined based on whether cookie is present as well as by checking the expiry data if cookie was present
      }

      componenDidMount() {
          const { permission } = this.state;
          const { dispatch } = this.props;
          if(permission.isPermissionGranted && !permission.isCookieExpired) {
             // Idea here is to populate the redux store based on localStorage value
             const state= JSON.parse(localStorage.get('REDUX_KEY'));
             dispatch({type: 'PERSISTOR_HYDRATE', payload: state})
          }

          // Adding a listner on window onLoad
          window.addEventListener('unload', (event) => {
             this.persistStateInLocalStorage();
          });
      }

      persistStateInLocalStorage = () => {
         const { storeState} = this.props;
         const {permission} = this.state;
         if(permission.isPermissionGranted && !permission.isCookieExpired) {
            localStorage.set('REDUX_KEY', JSON.stringify(storeState))
         }
      }
      componentWillUnmount() {
          this.persistStateInLocalStorage();
      }
      render() {
          const {children} = this.props;
          const {permission} = this.state;
          return (
            <React.Fragment>
               {children}
               {permission.isCookieExpired ? <Modal>{/*Pemission handling here*/}</Modal>}
            </React.Fragment>
          )

    }

const mapStateToProps = (state) => {
   return {
     storeState: state
   }
}
export default connect(mapStateToProps)(PermissionAndPersist);

После того, как вы реализуете вышеуказанный компонент, вам нужно прослушать действие PERSISTOR_HYDRATE в редукторе и обновить состояние редукса.

ПРИМЕЧАНИЕ: Возможно, вам придется добавить дополнительную обработку, чтобы сделать персистенцию и регидратацию правильной, но идея остается прежним

...