在 React 组件之外访问 redux 存储的最佳方式是什么?

IT技术 reactjs redux react-redux
2021-03-24 00:08:26

@connect当我尝试访问 react 组件中的 store 时效果很好。但是我应该如何在其他一些代码中访问它。例如:假设我想使用授权令牌来创建可以在我的应用程序中全局使用的 axios 实例,实现这一目标的最佳方法是什么?

这是我的 api.js

// tooling modules
import axios from 'axios'

// configuration
const api = axios.create()
api.defaults.baseURL = 'http://localhost:5001/api/v1'
api.defaults.headers.common['Authorization'] = 'AUTH_TOKEN' // need the token here
api.defaults.headers.post['Content-Type'] = 'application/json'

export default api

现在我想从我的商店访问一个数据点,如果我尝试在 React 组件中使用 @connect

// connect to store
@connect((store) => {
  return {
    auth: store.auth
  }
})
export default class App extends Component {
  componentWillMount() {
    // this is how I would get it in my react component
    console.log(this.props.auth.tokens.authorization_token) 
  }
  render() {...}
}

有什么见解或工作流程模式吗?

6个回答

从您调用的module中导出商店createStore然后你可以确信它会被创建并且不会污染全局窗口空间。

我的商店.js

const store = createStore(myReducer);
export store;

或者

const store = createStore(myReducer);
export default store;

我的客户端.js

import {store} from './MyStore'
store.dispatch(...)

或者如果您使用默认值

import store from './MyStore'
store.dispatch(...)

对于多个商店用例

如果您需要一个商店的多个实例,请导出工厂函数。我建议制作它async(返回 a promise)。

async function getUserStore (userId) {
   // check if user store exists and return or create it.
}
export getUserStore

在客户端(在一个async块中)

import {getUserStore} from './store'

const joeStore = await getUserStore('joe')
该问题也没有明确说明“浏览器”。由于 Redux 和 JavaScript 都可以在服务器或浏览器上使用,所以具体得多。
2021-05-23 00:08:26
同构应用程序警告:在服务器端执行此操作将在所有用户之间共享 redux 存储!!!
2021-06-13 00:08:26
导出 store 似乎会造成循环导入的噩梦,createStore 包括你的 reducer,它需要你的操作(至少是操作类型枚举和操作接口),它不能导入任何试图导入 store 的东西。所以你不能在你的减速器或动作中使用存储(或围绕循环导入以其他方式争论。)
2021-06-14 00:08:26
好吧,我对“访问 redux 商店”的解释是“阅读”商店。只是想帮助别人。
2021-06-18 00:08:26
这是正确的答案,但是如果您(像我一样)想要阅读而不是在商店中发送操作,则需要调用 store.getState()
2021-06-20 00:08:26

找到了解决办法。所以我在我的 api util 中导入商店并在那里订阅它。在该侦听器函数中,我使用新获取的令牌设置了 axios 的全局默认值。

这是我新的api.js样子:

// tooling modules
import axios from 'axios'

// store
import store from '../store'
store.subscribe(listener)

function select(state) {
  return state.auth.tokens.authentication_token
}

function listener() {
  let token = select(store.getState())
  axios.defaults.headers.common['Authorization'] = token;
}

// configuration
const api = axios.create({
  baseURL: 'http://localhost:5001/api/v1',
  headers: {
    'Content-Type': 'application/json',
  }
})

export default api

也许它可以进一步改进,因为目前它看起来有点不雅。我以后可以做的是向我的商店添加一个中间件,然后在那里设置令牌。

当我尝试访问组件或函数之外的商店时,我收到“TypeError: WEBPACK_IMPORTED_MODULE_2__store_js .b is undefined”。关于为什么会这样的任何帮助?
2021-05-25 00:08:26
你能分享一下你的store.js文件是什么样的吗?
2021-05-27 00:08:26
正是我正在寻找的东西,非常感谢@subodh
2021-05-30 00:08:26
我知道这个问题很老,但你可以接受你自己的答案是正确的。这使最终可能来到这里的其他人更容易找到您的答案。
2021-06-20 00:08:26
@Subodh,我认为它不再起作用了!
2021-06-21 00:08:26

您可以使用storecreateStore函数返回的对象(它应该已经在应用程序初始化的代码中使用)。您可以使用此对象通过store.getState()方法获取当前状态store.subscribe(listener)订阅存储更新。

window如果您真的需要,您甚至可以将此对象保存到属性以从应用程序的任何部分访问它(window.store = store

更多信息可以在Redux 文档中找到

我有多个 iframe 需要访问其他 iframe 的状态。我知道这有点 hacky,但我认为将商店放在窗口上会比使用 iframe 消息更好。有什么想法吗??@Vic @trashgenerator?
2021-06-09 00:08:26
听起来有点难保存storewindow
2021-06-21 00:08:26
@Vic 当然是 :) 通常你不想这样做。我只想提一下,你可以用这个变量做任何你想做的事情。可能最好的主意是将它存储在您创建“createStore”所在的文件中,然后从中导入。
2021-06-21 00:08:26

您可以Middleware根据如何访问非react组件中的商店?

中间件

function myServiceMiddleware(myService) {
  return ({ dispatch, getState }) => next => action => {
    if (action.type == 'SOMETHING_SPECIAL') {
      myService.doSomething(getState());
      myService.doSomethingElse().then(result => dispatch({ type: 'SOMETHING_ELSE', result }))
    }
    return next(action);
  }
}

用法

import { createStore, applyMiddleware } from 'redux'
const serviceMiddleware = myServiceMiddleware(myService)
const store = createStore(reducer, applyMiddleware(serviceMiddleware))

进一步阅读Redux 文档 > 中间件

如果您已经在全局范围内定义了 axios 实例,像 @sanchit 建议的中间件是一个不错的解决方案

您可以创建一个中间件,如:

function createAxiosAuthMiddleware() {
  return ({ getState }) => next => (action) => {
    const { token } = getState().authentication;
    global.axios.defaults.headers.common.Authorization = token ? `Bearer ${token}` : null;

    return next(action);
  };
}

const axiosAuth = createAxiosAuthMiddleware();

export default axiosAuth;

并像这样使用它:

import { createStore, applyMiddleware } from 'redux';
const store = createStore(reducer, applyMiddleware(axiosAuth))

它会在每个动作上设置令牌,但您只能监听例如更改令牌的动作。

如何使用自定义 axios 实例实现相同的目标?
2021-05-22 00:08:26