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


192

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

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


Axios 인스턴스가 redux 미들웨어에 살고 싶지 않습니까? 이 방법은 모든 응용 프로그램에서 사용할 수 있습니다
Emrys Myrooin

클래스 api내에서 가져올 수 있고 App권한 부여 토큰을 얻은 후에도 할 수 api.defaults.headers.common['Authorization'] = this.props.auth.tokens.authorization_token;있으며, 동시에 localStorage에도 저장할 수 있으므로 사용자가 페이지를 새로 고칠 때 localStorage에 토큰이 있는지 여부와 토큰이 있는지 여부를 확인할 수 있습니다. 당신이 그것을 설정할 수 있습니다., 나는 그것을 얻는 즉시 api 모듈에 토큰을 설정하는 것이 가장 좋을 것이라고 생각합니다.
Dhruv Kumar Jha

1
Dan Abromov는 이슈 큐에 예제를 제공합니다 : github.com/reactjs/redux/issues/916
chrisjlee

1
특정 감속기에서 특정 상태에 액세스해야하는 경우 redux-named-reducers 를 사용하여 어디에서나 최신 상태에 액세스 할 수 있습니다.
miles_christian

답변:


146

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

47
동형 응용 프로그램에 대한 경고 :이 서버 측을 수행하면 모든 사용자가 redux 저장소를 공유합니다!
Lawrence Wagerfield

6
이 질문에는 명시 적으로 "브라우저"도 명시되어 있지 않습니다. Redux와 JavaScript는 모두 서버 나 브라우저에서 사용할 수 있으므로 구체적으로 사용하는 것이 훨씬 안전합니다.
Lawrence Wagerfield

7
내보내기 저장소는 주기적 가져 오기의 악몽을 만드는 것 같습니다. createStore에는 저장소를 가져 오는 것을 가져 와서는 안되는 조치 (적어도 조치 유형 열거 및 조치 인터페이스)가 필요한 리듀서가 포함됩니다. 따라서 리듀서 또는 조치에 상점을 사용하거나 주기적 반입에 다른 방식으로 얽혀서는 안됩니다.
Eloff

6
이 정답이지만, (나 같은) 당신이 파견 대신 가게에서 작업을 읽으려면, 당신은 호출 할 필요가store.getState()
후안 호세 라미레즈

3
"access redux store"에 대한 나의 해석은 그 상점을 "읽었다". 다른 사람들을 돕기 위해 노력하고 있습니다.
Juan José Ramírez

47

해결책을 찾았습니다. 그래서 내 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

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


1
store.js파일 모양 을 공유 할 수 있습니까?
Vic

내가 찾던 정확히 @subodh 덕분에
Harkirat Saluja

1
질문이 오래되었다는 것을 알고 있지만 자신의 답변을 올바른 것으로 받아 들일 수 있습니다. 이렇게하면 결국 여기에 올 수도있는 다른 사람들이 쉽게 답을 찾을 수 있습니다.
Filipe Merker

3
구성 요소 나 함수 외부의 상점에 액세스하려고하면 "TypeError : WEBPACK_IMPORTED_MODULE_2__store_js .b is undefined"가 표시됩니다. 그 이유에 대한 도움이 필요하십니까?
ben

21

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

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

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


19
저장 좀 해키 소리 store받는 사람window

3
@Vic 물론입니다 :) 그리고 일반적으로 당신은 그것을하고 싶지 않습니다. 이 변수로 원하는 것을 할 수 있다고 언급하고 싶었습니다. 아마도 가장 좋은 아이디어는 "createStore"를 생성 한 위치에 파일을 저장 한 다음 가져 오는 것입니다.
휴지통 생성기

다른 iframe의 상태에 액세스해야하는 여러 iframe이 있습니다. 나는 그것이 다소 해 키다는 것을 알고 있지만 창에 상점을 두는 것이 iframe에 메시지를 사용하는 것보다 낫다고 생각합니다. 이견있는 사람?? @Vic @trashgenerator?
Sean Malter


10

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

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


커스텀 axios 인스턴스로 어떻게 같은 결과를 얻을 수 있습니까?
Anatol

3

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

3
투표를 거부하는 경우 이유를 추가하십시오.
Ogglas December

3
귀하의 답변에 설명이 부족하고 Javascript 대신 TypeScript를 사용하기 때문에 투표에 실패했습니다.

2
@Will 이유를 말씀해 주셔서 감사합니다. Imao 코드에는 사양이 필요하지 않지만 특정 설명이 필요한 경우 무엇을 말하십시오. TypeScript가 실제로 사용되지만 입력이 제거되면 동일한 코드가 문제없이 ES6에서 실행됩니다.
Ogglas

서버 측 렌더링을 수행하는 경우 이는 매우 좋지 않으며 모든 요청과 상태를 공유합니다.
롭 에반스

2

조금 늦을 수도 있지만 가장 좋은 방법은 사용하는 것입니다. 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)
    );
}

1

갈고리로 해. 비슷한 문제가 발생했지만 후크가있는 반응 리덕스를 사용하고있었습니다. 매장에서 정보를 검색 / 보내기위한 전용 코드가 많은 인터페이스 코드 (예 : 컴포넌트 반응)를 처리하고 싶지 않았습니다. 오히려 데이터를 검색하고 업데이트하기 위해 일반 이름을 가진 함수가 필요했습니다. 내 길은 앱을

const store = createSore(
   allReducers,
   window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
 );

store.js에서 일반적인 react-redux 가져 오기를 추가하고 이전에 store.js추가 한 모듈에 추가합니다. 파일. 그런 다음 앱 수준으로 가져 왔으며 평소와 같이 index.js로 가져 왔습니다. 그러면 하위 구성 요소가 및exportconstindex.jsimport {store} from "./store.js"useSelector()useDispatch() 후크를 .

비 구성 요소 프론트 엔드 코드에서 저장소에 액세스하기 위해, 나는 유사한 수입 (즉, 사용 import {store} from "../../store.js") 한 후 사용 store.getState()store.dispatch({*action goes here*})처리 가게를 (에 작업을 전송, 어) 검색 및 업데이트에 있습니다.


0

토큰에 쉽게 액세스 할 수있는 방법은 토큰을 LocalStorage 또는 React Native가있는 AsyncStorage에 넣는 것입니다.

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 대신 사용할 수 있습니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.