Подтвердить что ты не робот

Каков наилучший способ доступа к хранилищу редуктов вне реагирующего компонента?

@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() {...}
}

Любые идеи или шаблоны рабочих процессов там?

4b9b3361

Ответ 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.

Ответ 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