Каков наилучший способ доступа к хранилищу редуктов вне реагирующего компонента?
@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
Теперь я хочу получить доступ к точке данных из своего хранилища, вот что бы выглядело, если бы я пытался получить ее внутри реагирующего компонента, используя @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() {...}
}
Любые идеи или шаблоны рабочих процессов там?
Ответы
Ответ 1
Экспортируйте хранилище из модуля, который вы назвали createStore
. Тогда вы уверены, что он будет создан и не будет загрязнять пространство глобального окна.
MyStore.js
const store = createStore(myReducer);
export store;
или же
const store = createStore(myReducer);
export default store;
MyClient.js
import {store} from './MyStore'
store.dispatch(...)
или если вы использовали по умолчанию
import store from './MyStore'
store.dispatch(...)
Для нескольких случаев использования магазина
Если вам нужно несколько экземпляров магазина, экспортируйте фабричную функцию. Я бы порекомендовал сделать это async
(возвращая 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')
Ответ 2
Найден решение. Поэтому я импортирую хранилище в свой 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
Возможно, он может быть еще лучше, потому что в настоящее время он кажется немного неэлегантным. То, что я могу сделать позже, - добавить промежуточное ПО в мой магазин и установить токен тогда и там.
Ответ 3
Вы можете использовать объект store
который возвращается из функции createStore
(которая уже должна использоваться в вашем коде при инициализации приложения). Затем вы можете использовать этот объект для получения текущего состояния с store.getState()
метода store.getState()
или store.subscribe(listener)
для подписки на обновления магазина.
Вы даже можете сохранить этот объект в свойстве window
чтобы получить к нему доступ из любой части приложения, если вы действительно этого хотите (window.store = store
)
Больше информации можно найти в документации Redux.
Ответ 4
Похоже, Middleware
это путь.
Ссылайтесь на официальную документацию и этот вопрос на репо
Ответ 5
Как и @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;
И используйте это так:
import { createStore, applyMiddleware } from 'redux';
const store = createStore(reducer, applyMiddleware(axiosAuth))
Он будет устанавливать токен на каждое действие, но вы можете прослушивать только действия, которые меняют токен, например.
Ответ 6
Для TypeScript 2.0 это будет выглядеть так:
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(...)}
Ответ 7
Простой способ получить доступ к токену - это поместить токен в LocalStorage или AsyncStorage с React Native.
Ниже приведен пример с проектом 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;
}
};
...
и 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 };
Для веб вы можете использовать Window.localStorage
вместо AsyncStorage