Reactjs URL哈希和Redux状态的双向绑定

Reactjs URL哈希和Redux状态的双向绑定,reactjs,redux,react-router,react-redux,Reactjs,Redux,React Router,React Redux,我现在正在学习Redux和React,我正在写一个像这样的爱好项目 该项目是一个使用标记进行搜索的搜索服务。用户可以在UI中添加或删除标记。在代码中,标记以Redux状态表示,添加和删除标记通过单独的操作进行。到目前为止还不错,我有一个玩具代码可以使用 现在我想用哈希之后的URL部分“绑定”标签;例如,序列化标记,用破折号分隔;这样用户就可以复制/粘贴URL并拥有相同的标记 我不知道如何轻松地做到这一点 我总是点击一个叫做“react router”的东西,但我在示例中看到的是,总是有更多的输入

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

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

现在我想用哈希之后的URL部分“绑定”标签;例如,序列化标记,用破折号分隔;这样用户就可以复制/粘贴URL并拥有相同的标记

我不知道如何轻松地做到这一点

我总是点击一个叫做“react router”的东西,但我在示例中看到的是,总是有更多的输入点指向应用程序,并根据散列向用户显示应用程序的不同部分。我不想那样。所以我不知道我是否真的需要这个路由器;我不想走任何路线

即使我想要这个,我也找不到如何将Redux状态与URL绑定。我不想将标签直接注入组件的道具;我希望url中的标记处于Redux状态

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


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

您应该收听hashchange事件,并在其更改后更新状态。要执行双向绑定,还应侦听状态更改,并在状态更改后更新窗口哈希。这就是它的工作原理():


我受Alexander Bykov的answer+redux persist的启发,制作了这个-一个增强器,可以实现hashstore的双向绑定

这样使用:

export const store = createStore(
    reducer,
    initialState,
    hashEnhancer(hashFromState, stateFromStateAndHash)
);
其中hashFromState是hash=>state类型的函数,stateFromStateAndHash是function(state,hash)=>state


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

用react-Router-redux检查此示例。此示例与最新的react-Router不兼容我制作了一种增强剂,它也可以这样做,但是我会选择你的答案,因为我复制了最重要的部分
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)
);