【问题标题】:Two way binding of URL hash and Redux stateURL hash 和 Redux 状态的两种方式绑定
【发布时间】:2017-11-23 16:37:00
【问题描述】:

我现在正在学习 Redux 和 React,我正在编写一个像这样工作的爱好项目。

该项目是一个使用标签进行搜索的搜索服务。用户可以在 UI 中添加或删除标签。在代码中,标签以 Redux 状态表示,添加和删除标签是通过单独的操作发生的。到目前为止一切顺利,我有一个有效的玩具代码。

现在我想以某种方式将标签与散列之后的 URL 部分“绑定”;例如,序列化标签,用破折号分隔;以便用户可以复制/粘贴 URL 并具有相同的标签。

我找不到如何轻松做到这一点。

我总是遇到一种叫做“反应路由器”的东西,但我在示例中看到的只是应用程序的输入点更多,并根据哈希值向用户显示应用程序的不同部分。我不想要那个。所以我不知道我是否真的需要这个路由器;我不想路由任何东西。

即使我想要这个,我也找不到如何将 Redux 状态与 URL 绑定。我不想将标签直接注入到组件的 props 中;我想要来自 Redux 状态的 url 的标签。

感觉好像我做错了什么,我需要重新考虑我的整体设计,但我不知道从哪里开始。

(我没有添加任何实际代码,因为我认为这是关于应用程序设计的更普遍的问题,但我可以稍后简化我的玩具代码并将其粘贴在这里)

【问题讨论】:

标签: reactjs redux react-router react-redux


【解决方案1】:

我受到 Alexander Bykov 的回答 + redux-persist 的启发,并制作了这个 - 一个增强器,可以实现哈希的双向绑定store。

import { applyMiddleware } from 'redux';
import createActionBuffer from 'redux-action-buffer';

const CHANGE_HASH = '@@hashSynch/CHANGE_HASH';
const hashEnhancer = (hashFromState, stateFromStateAndHash) => createStore => (reducer, initialState) => {
  const store = createStore(liftReducer(reducer), initialState, applyMiddleware(createActionBuffer(CHANGE_HASH)));
  store.subscribe(() => {
    const hash = hashFromState(store.getState());
    if (window.location.hash !== hash) {
        window.location.hash = hash;
    }
  });

  window.addEventListener('hashchange', () => {
    const hash = window.location.hash;
    const savedHash = hashFromState(store.getState());
    if (savedHash !== hash) {
      store.dispatch({
        type: CHANGE_HASH,
        hash
      });
    }
  }, false);

  store.dispatch({
    type: CHANGE_HASH,
    hash: window.location.hash
  });

  function liftReducer(reducer) {
    return (state, action) => {
      if (action.type !== CHANGE_HASH) {
        return reducer(state, action);
      } else {
        return stateFromStateAndHash(state, action.hash);
      }
    }
  }

  return {
    ...store,
    replaceReducer: (reducer) => {
      return store.replaceReducer(liftReducer(reducer))
    }
  }
};

这样使用:

export const store = createStore(
    reducer,
    initialState,
    hashEnhancer(hashFromState, stateFromStateAndHash)
);

其中 hashFromState 是 hash=>state 类型的函数,stateFromStateAndHash 是 function (state, hash) => state。

它可能是过度设计的,而路由器会更简单,我根本不了解 react-router 或 react-router-redux。

【讨论】:

    【解决方案2】:

    你应该监听 hashchange 事件并在它改变后更新状态。要执行双向绑定,您还应该侦听状态更改并在状态更改后更新窗口哈希。这是它如何工作的想法(fiddle):

    function changeHash(state = '', action) {
      if(action.type == 'CHANGE_HASH')
        return action.hash;
    
      return state;
    }
    
    const store = Redux.createStore(changeHash);
    
    store.subscribe(() => {
      const hash = store.getState();
      if (window.location.hash !== hash) {
        window.location.hash = hash;
        console.log('State changed: ' + hash);
      }
    });
    
    window.addEventListener("hashchange", () => {
      const hash = window.location.hash;
      if (store.getState() !== hash) {
        store.dispatch({
          type: 'CHANGE_HASH',
          hash
        });
        console.log('Hash changed: ' + hash);
      }
    }, false);
    
    setTimeout(() => {
        store.dispatch({
        type: 'CHANGE_HASH',
        hash: '#changed-state'
      });
    }, 3000);
    
    setTimeout(() => {
        window.location.hash = '#changed-hash';
    }, 6000);
    

    【讨论】:

    • 用 react-router-redux fiddle.jshell.net/omerts/r9dbgsjj检查这个示例
    • 该示例不适用于最新的 react-router
    • 我做了一个同样的增强器,但我会选择你的答案,因为我复制了那里最重要的部分
    猜你喜欢
    • 1970-01-01
    • 2016-02-27
    • 2017-09-05
    • 2014-02-13
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多