[reactjs] 반응 구성 요소 외부에서 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

어쩌면 더 개선 될 수 있습니다. 현재 약간 우아하지 않은 것처럼 보입니다. 나중에 할 수있는 일은 미들웨어를 내 상점에 추가하고 토큰을 설정하는 것입니다.


답변

함수 store에서 반환 된 객체를 사용할 수 있습니다 createStore(앱 초기화의 코드에서 이미 사용되어야 함). 이 객체를 사용하여 store.getState()메소드 또는store.subscribe(listener) 상점 업데이트를 구독 할 수 있습니다.

이 객체를 저장할 수도 있습니다 window 속성에 원하는 경우 응용 프로그램의 어느 부분에서나 액세스 할 수 있습니다 (window.store = store )

자세한 내용은 Redux 설명서를 참조하십시오 .


답변

Middleware가는 길인 것 같습니다 .
참조 공식 문서이 문제를 자신의 repo에


답변

@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))

모든 액션에 토큰을 설정하지만 토큰을 변경하는 액션 만들을 수 있습니다.


답변

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


답변

조금 늦을 수도 있지만 가장 좋은 방법은 사용하는 것입니다. axios.interceptors 다음과 같이 하는 것입니다. 가져 오기 URL은 프로젝트 설정에 따라 변경 될 수 있습니다.

index.js

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

// some other codes

setupAxios(axios, store);

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