script react helmet reactjs redux react-redux

reactjs - helmet - ¿Cuál es la mejor manera de acceder a la tienda redux fuera de un componente reactivo?



react meta tags (7)

Al igual que @sanchit, el middleware propuesto es una buena solución si ya está definiendo su instancia de axios a nivel mundial.

Puedes crear un middleware como:

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;

Y úsalo así:

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

Establecerá el token en cada acción, pero solo puede escuchar acciones que cambien el token, por ejemplo.

@connect funciona muy bien cuando intento acceder a la tienda dentro de un componente de reacción. Pero, ¿cómo debo acceder a él en algún otro bit de código? Por ejemplo: supongamos que quiero usar un token de autorización para crear mi instancia de axios que pueda usarse globalmente en mi aplicación, ¿cuál sería la mejor manera de lograrlo?

Esta es mi 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

Ahora quiero acceder a un punto de datos desde mi tienda, así es como se vería si estuviera tratando de recuperarlo dentro de un componente de reacción usando @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() {...} }

¿Alguna idea o patrones de flujo de trabajo por ahí?


Encontró una solución. Así que importo la tienda en mi api util y me suscribo allí. Y en esa función de escucha configuré los valores predeterminados globales de los axios con mi token recién obtenido.

Así es como se ve mi nuevo 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

Tal vez se pueda mejorar aún más, porque actualmente parece un poco poco elegante. Lo que podría hacer más tarde es agregar un middleware a mi tienda y configurar el token allí mismo.


Exporte la tienda desde el módulo con el que llamó createStore . Entonces tiene la seguridad de que ambos se crearán y no contaminarán el espacio de la ventana global.

MyStore.js

const store = createStore(myReducer); export store;

o

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

MyClient.js

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

o si usaste por defecto

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

Para casos de uso de múltiples tiendas

Si necesita varias instancias de una tienda, exporte una función de fábrica. Recomendaría hacerlo async (devolver una promise ).

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

En el cliente (en un bloque async )

import {getUserStore} from ''./store'' const joeStore = await getUserStore(''joe'')


Para TypeScript 2.0 se vería así:

MyStore.ts

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;

MyClient.tsx

import reduxStore from "../Store"; {reduxStore.dispatch(...)}



Puede usar el objeto de store que se devuelve desde la función createStore (que ya debería usarse en su código en la inicialización de la aplicación). Entonces puede usar este objeto para obtener el estado actual con el método store.getState() o store.subscribe(listener) para suscribirse a las actualizaciones de la tienda.

Incluso puede guardar este objeto en la propiedad de window para acceder a él desde cualquier parte de la aplicación si realmente lo desea ( window.store = store )

Se puede encontrar más información en la documentación de Redux .


Una manera fácil de tener acceso al token es colocar el token en LocalStorage o AsyncStorage con React Native.

Debajo de un ejemplo con un proyecto React Native

authReducer.js

import { AsyncStorage } from ''react-native''; ... const auth = (state = initialState, action) => { switch (action.type) { case SUCCESS_LOGIN: AsyncStorage.setItem(''token'', action.payload.token); return { ...state, ...action.payload, }; case REQUEST_LOGOUT: AsyncStorage.removeItem(''token''); return {}; default: return state; } }; ...

y api.js

import axios from ''axios''; import { AsyncStorage } from ''react-native''; const defaultHeaders = { ''Content-Type'': ''application/json'', }; const config = { ... }; const request = axios.create(config); const protectedRequest = options => { return AsyncStorage.getItem(''token'').then(token => { if (token) { return request({ headers: { ...defaultHeaders, Authorization: `Bearer ${token}`, }, ...options, }); } return new Error(''NO_TOKEN_SET''); }); }; export { request, protectedRequest };

Para la web, puede usar Window.localStorage lugar de AsyncStorage