在反应组件外部访问redux存储的最佳方法是什么?

Sub*_*eek 163 reactjs redux react-redux

@connect当我试图在反应组件中访问商店时,效果很好.但是我应该如何在其他一些代码中访问它.例如:假设我想使用授权令牌来创建可以在我的应用程序中全局使用的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
Run Code Online (Sandbox Code Playgroud)

现在我想从我的商店访问一个数据点,如果我试图在反应组件中使用它来获取它,那么这就是 @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() {...}
}
Run Code Online (Sandbox Code Playgroud)

那里有任何见解或工作流程模式吗?

Ste*_*gin 133

从您调用createStore的模块导出存储.然后你可以肯定它将被创建并且不会污染全局窗口空间.

MyStore.js

const store = createStore(myReducer);
export store;
Run Code Online (Sandbox Code Playgroud)

要么

const store = createStore(myReducer);
export default store;
Run Code Online (Sandbox Code Playgroud)

MyClient.js

import {store} from './MyStore'
store.dispatch(...)
Run Code Online (Sandbox Code Playgroud)

或者如果您使用默认值

import store from './MyStore'
store.dispatch(...)
Run Code Online (Sandbox Code Playgroud)

对于多个商店用例

如果需要多个商店实例,请导出工厂函数.我建议制作它createStore(返回async).

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

在客户端(在一个promise块(

import {getUserStore} from './store'

const joeStore = await getUserStore('joe')
Run Code Online (Sandbox Code Playgroud)

  • 警告同构应用程序:执行此服务器端将共享所有用户的redux存储! (44认同)
  • 问题也没有明确说明"浏览器".由于Redux和JavaScript都可以在服务器或浏览器上使用,因此具体更安全. (6认同)
  • 导出存储似乎创建了一个循环导入的噩梦,createStore包含你的reducers,它需要你的动作(至少是动作类型枚举和Action接口),它们不能导入任何试图导入存储的东西.因此,您不能在reducers或actions中使用store(或者在循环导入时以其他方式进行争论.) (5认同)
  • 这是正确的答案,但如果你(像我一样)想要阅读而不是在商店中调度一个动作,你需要调用`store.getState()` (5认同)
  • 好吧,我对"访问redux商店"的解读是"阅读"商店.只是想帮助别人. (3认同)

Sub*_*eek 40

找到了解决方案.所以我在我的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
Run Code Online (Sandbox Code Playgroud)

也许它可以进一步改进,因为目前它似乎有点不优雅.我以后可以做的是在我的商店中添加一个中间件,然后设置令牌.

  • 你能分享一下你的“store.js”文件是什么样子的吗? (2认同)
  • 我知道这个问题很旧,但您可以接受自己的答案是正确的。这使得最终可能来到这里的其他人更容易找到您的答案。 (2认同)
  • 当我尝试访问组件或函数外部的存储时,出现“ TypeError:__WEBPACK_IMPORTED_MODULE_2__store_js __。b未定义”。有什么帮助吗? (2认同)

tra*_*tor 18

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

你甚至可以将这个对象保存到window属性,以便从应用程序的任何部分访问它,如果你真的想要它(window.store = store)

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

  • 听起来有点hacky将`store`保存到`window` (16认同)
  • @Vic肯定是:)而且通常你不想这样做.我只想提一下,你可以用这个变量做任何你想做的事情.可能最好的想法是将它存储在您创建"createStore"生活的文件中,然后从中导入. (3认同)

san*_*hit 10

似乎Middleware是要走的路.在他们的回购中
参考官方文档这个问题


Cha*_*win 8

用钩子来做。我遇到了类似的问题,但我正在使用带有钩子的react-redux。我不想在我的界面代码(即反应组件)中加入大量专门用于从商店检索信息/向商店发送信息的代码。相反,我想要具有通用名称的函数来检索和更新数据。我的路径是将应用程序的

const store = createSore(
   allReducers,
   window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
 );
Run Code Online (Sandbox Code Playgroud)

到一个名为store.js并添加export之前的模块中const,并在 store.js 中添加常用的react-redux 导入。文件。index.js然后,我在应用程序级别导入,然后使用通常的import {store} from "./store.js"子组件将其导入到 index.js 中,然后使用useSelector()useDispatch()钩子访问存储。

为了在非组件前端代码中访问存储,我使用了类似的导入(即import {store} from "../../store.js"),然后使用store.getState()store.dispatch({*action goes here*})来处理存储的检索和更新(呃,发送操作)。


erk*_*sch 7

像@sanchit一样,如果你已经在全球范围内定义了axios实例,那么提出的中间件是一个不错的解决方案.

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

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;
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

import { createStore, applyMiddleware } from 'redux';
const store = createStore(reducer, applyMiddleware(axiosAuth))
Run Code Online (Sandbox Code Playgroud)

它将在每个操作上设置令牌,但您只能侦听更改令牌的操作.


Ogg*_*las 5

对于 TypeScript 2.0,它看起来像这样:

我的商店

export namespace Store {

    export type Login = { isLoggedIn: boolean }

    export type All = {
        login: Login
    }
}

import { reducers } from '../Reducers'
import * as Redux from 'redux'

const reduxStore: Redux.Store<Store.All> = Redux.createStore(reducers)

export default reduxStore;
Run Code Online (Sandbox Code Playgroud)

我的客户.tsx

import reduxStore from "../Store";
{reduxStore.dispatch(...)}
Run Code Online (Sandbox Code Playgroud)

  • 如果您投反对票,请添加评论原因。 (6认同)
  • 投反对票是因为您的回答缺乏解释并使用 TypeScript 而不是 Javascript。 (3认同)
  • @Will 谢谢你说出原因。Imao 代码不需要规范,但如果你想解释一些具体的内容,请说明什么。确实使用了 TypeScript,但如果删除类型,则相同的代码将在 ES6 中运行而不会出现问题。 (2认同)

Mer*_*sek 5

可能有点晚了,但我认为最好的方法是使用axios.interceptors如下。导入 url 可能会根据您的项目设置而改变。

索引.js

import axios from 'axios';
import setupAxios from './redux/setupAxios';
import store from './redux/store';

// some other codes

setupAxios(axios, store);
Run Code Online (Sandbox Code Playgroud)

设置Axios.js

export default function setupAxios(axios, store) {
    axios.interceptors.request.use(
        (config) => {
            const {
                auth: { tokens: { authorization_token } },
            } = store.getState();

            if (authorization_token) {
                config.headers.Authorization = `Bearer ${authorization_token}`;
            }

            return config;
        },
       (err) => Promise.reject(err)
    );
}
Run Code Online (Sandbox Code Playgroud)


小智 5

导出我的商店变量

导出 const store = createStore(rootReducer, applyMiddleware(ReduxThunk));

在操作文件或您的文件中需要导入此(存储)

从“./path...”导入{store};

这一步使用函数从存储变量中获取状态

const state = store.getState();

并获取您的应用程序的所有状态