Programming

반응 구성 요소 외부에서 Redux Store에 액세스하는 가장 좋은 방법은 무엇입니까?

procodes 2020. 6. 3. 22:51
반응형

반응 구성 요소 외부에서 Redux Store에 액세스하는 가장 좋은 방법은 무엇입니까?


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

통찰력이나 워크 플로 패턴이 있습니까?


호출 한 모듈에서 상점을 내보내십시오 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')

해결책을 찾았습니다. 그래서 내 API 유틸리티에서 상점을 가져 와서 구독하십시오. 그리고 그 리스너 기능에서 새로 가져온 토큰으로 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

어쩌면 그것은 조금 더 개선 될 수 있습니다. 나중에 할 수있는 일은 미들웨어를 내 상점에 추가하고 토큰을 설정하는 것입니다.


You can use store object that is returned from createStore function (which should be already used in your code in app initialization). Than you can use this object to get current state with store.getState() method or store.subscribe(listener) to subscribe to store updates.

You can even save this object to window property to access it from any part of application if you really want it (window.store = store)

More info can be found in the Redux documentation .


Seems like Middleware is the way to go.
Refer the official documentation and this issue on their repo


Like @sanchit proposed middleware is a nice solution if you are already defining your axios instance globally.

You can create a middleware like:

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;

And use it like this:

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

It will set the token on every action but you could only listen for actions that change the token for example.


For TypeScript 2.0 it would look like this:

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

An easy way to have access to the token, is to put the token in the LocalStorage or the AsyncStorage with React Native.

Below an example with a React Native project

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;
  }
};
...

and 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 };

For web you can use Window.localStorage instead of AsyncStorage

참고URL : https://stackoverflow.com/questions/38460949/what-is-the-best-way-to-access-redux-store-outside-a-react-component

반응형