@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 설명서를 참조하십시오 .
답변
답변
@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)
);
}