在使用 LocalStorage 之前,我希望通过单击横幅按钮来获得用户的同意。 LocalStorage 通过 redux-persist 使用。我使用 reduxredux-persist 如下:

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

storepersistor来自

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 组件中使用 redux,无论状态是否持久。

我认为 reducer 的细节并不重要,因为它不会影响状态的存储位置/方式。

用户曾经明确同意使用LocalStorage和cookie的信息将存储在cookie中。

仅当用户在第一次访问期间表示同意或 cookie 已存在时,我如何才能开始使用 LocalStorage 进行持久化? cookie过期或已被删除的情况应包含在首次访问的情况中。

为了尽量减少讨论,我正在寻找解决技术问题的解决方案。就法律要求而言,该请求可能有些过分。

到目前为止我尝试过的事情:

  • 使用两个存储(可能是不好的做法),它们在包装 ProviderApp 组件的状态下进行管理,如示例所示。问题是,一旦单击横幅按钮,页面就会重新呈现,这是 Not Acceptable 。
  • 已评估黑名单,但该黑名单不起作用,因为它对状态的初始持久性没有影响。
<小时 />

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

请您参考如下方法:

这里的想法是 redux-persist 的 persistor 组件负责在 localStorage 中持久保存数据或 redux 状态。

为了根据用户的同意做出决定,您需要有条件地渲染或不渲染PersistGate组件

要解决此类问题,您可以在 Persistor 上编写一个自定义组件,该组件仅在授予权限时才呈现它。此外,提示用户授予或拒绝权限的逻辑可以放在同一组件中

示例

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。其次,我们不能有条件地更改重新渲染的组件,否则整个应用程序都会刷新。目前实现它的唯一方法是实际实现自己在 localStorage 中保留 redux 状态的逻辑,并在刷新时首先获取它

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); 

实现上述组件后,您需要在reducer中监听PERSISTOR_HYDRATE操作并更新redux状态。

注意:您可能需要添加更多处理才能正确保存和再水合,但想法保持不变


评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!