Bir tepki bileşeninin dışındaki redux mağazasına erişmenin en iyi yolu nedir?


192

@connectbir tepki bileşeninde mağazaya erişmeye çalıştığımda harika çalışıyor. Ancak başka bir kod parçasında nasıl erişmeliyim. Örneğin: diyelim ki, uygulamamda global olarak kullanılabilecek axios örneğimi oluşturmak için bir yetkilendirme belirteci kullanmak istiyorum, bunu başarmanın en iyi yolu nedir?

Bu benim 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

Şimdi mağazamdan bir veri noktasına erişmek istiyorum, işte bir tepki bileşeni içinde onu almaya çalışsaydım şöyle görünüyordu @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() {...}
}

Herhangi bir içgörü veya iş akışı paterni var mı?


Axios örneğinizin redux ara katman yazılımında yaşamasını istemiyor musunuz? Tüm uygulamanız tarafından bu şekilde kullanılabilir olacak
Emrys Myrooin

Sen alabilirsiniz apiyılında Appsınıf ve yapabileceğiniz simge izinlerin alınmasını müteakip api.defaults.headers.common['Authorization'] = this.props.auth.tokens.authorization_token;, Ve aynı zamanda sen localStorage içinde saklayabilir, hem de belirteç localStorage içinde ve ona eğer varsa bu yüzden kullanıcı yenilenir sayfasında, kontrol edebilirsiniz zaman yaparsanız, ayarlayabilirsiniz., Ben en kısa sürede almak olsun api modülü belirteç ayarlamak için en iyi olacağını düşünüyorum.
Dhruv Kumar Jha

1
Dan Abromov, buradaki sorun kuyruğunda bir örnek sunuyor: github.com/reactjs/redux/issues/916
chrisjlee

1
Belirli bir indirgeyiciden belirli bir duruma erişmeniz gerekiyorsa, redux adlı indirgeyicileri deneyerek en son duruma her yerden erişmenizi sağlar.
miles_christian

Yanıtlar:


146

Mağazayı, aradığınız modülden dışa aktarın createStore. O zaman ikisinin de yaratılacağından ve küresel pencere alanını kirletmeyeceğinden emin olabilirsiniz.

MyStore.js

const store = createStore(myReducer);
export store;

veya

const store = createStore(myReducer);
export default store;

MyClient.js

import {store} from './MyStore'
store.dispatch(...)

veya varsayılanı kullandıysanız

import store from './MyStore'
store.dispatch(...)

Çoklu Mağaza Kullanım Durumları için

Bir mağazanın birden fazla örneğine ihtiyacınız varsa, fabrika işlevini dışa aktarın. async(A dönen promise) yapma tavsiye ederim .

async function getUserStore (userId) {
   // check if user store exists and return or create it.
}
export getUserStore

İstemcide (bir asyncblokta)

import {getUserStore} from './store'

const joeStore = await getUserStore('joe')

47
İzomorfik uygulamalar için UYARI: Bu sunucu tarafını yapmak redux mağazasını tüm kullanıcılarınızda paylaşacaktır !!!
Lawrence Wagerfield

6
Soru ayrıca "tarayıcıyı" açıkça belirtmiyor. Hem Redux hem de JavaScript sunucuda veya tarayıcıda kullanılabileceğinden, spesifik olmak çok daha güvenlidir.
Lawrence Wagerfield

7
ihracatçı mağaza döngüsel ithalat kabusu oluşturuyor gibi görünüyor, createStore, mağaza ithal etmeye çalışan hiçbir şeyi ithal etmemesi gereken eylemlerinizi (en azından eylem türü enum ve Eylem arayüzleri) gerektiren redüktörlerinizi içerir. Bu yüzden mağazayı indirgeyicilerinizde veya eylemlerinizde kullanmamalısınız (veya döngüsel içe aktarma etrafında başka bir yolla
savaşmamalısınız

6
Bu doğru cevaptır, ancak (benim gibi) mağazada bir eylem göndermek yerine okumak istiyorsanız, aramalısınızstore.getState()
Juan José Ramírez

3
"Access redux store" hakkındaki yorumum mağazayı "read" idi. Sadece başkalarına yardım etmeye çalışıyorum.
Juan José Ramírez

47

Bir çözüm buldum. Bu yüzden api util benim mağaza almak ve orada abone. Ve bu dinleyici fonksiyonunda, yeni getirilen jetonumla aksiyomların global varsayılanlarını ayarladım.

Bu benim yeni api.jsgibi görünüyor:

// 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

Belki daha da geliştirilebilir, çünkü şu anda biraz yetersiz görünüyor. Daha sonra yapabileceğim mağazama bir ara katman eklemek ve jetonu oraya oraya ayarlamak.


1
store.jsdosyanızın nasıl göründüğünü paylaşabilir misiniz?
Vic

tam olarak aradığım bir şey, teşekkürler bir ton @subodh
Harkirat Saluja

1
Sorunun eski olduğunu biliyorum, ancak kendi cevabınızı doğru olarak kabul edebilirsiniz. Bu, sonuçta buraya gelebilecek başkalarını bulmak için cevabınızı kolaylaştırır.
Filipe Merker

3
Bir bileşenin veya işlevin dışındaki mağazaya erişmeye çalıştığımda "TypeError: WEBPACK_IMPORTED_MODULE_2__store_js .b tanımsız" aldım. Bunun neden olduğu hakkında herhangi bir yardım?
ben

21

Kullanabilirsiniz store döndürülen nesneyicreateStore (uygulama başlatma işleminde kodunuzda zaten kullanılmalıdır). Daha sonra bu nesneyi store.getState()yöntemle geçerli durumu almak veya store.subscribe(listener)güncellemeleri depolamak için kullanabilirsiniz.

Gerçekten isterseniz, bu nesneyi windowuygulamanın herhangi bir bölümünden erişmek için özelliğe de kaydedebilirsiniz ( window.store = store)

Daha fazla bilgi Redux belgelerinde bulunabilir .


19
kulağa kurtarmak storeiçin biraz kaba geliyorwindow
Vic

3
@Vic Tabii ki :) Ve normalde bunu yapmak istemezsiniz. Sadece bu değişkenle ne istersen yapabileceğinden bahsetmek istedim. Muhtemelen en iyi fikir, onu "createStore" yaşamlarınızı oluşturduğunuz dosyada saklamak ve daha sonra ondan almak olacaktır.
çöp kutusu

Diğer iframe'lerin durumuna erişmesi gereken birden fazla iframe'im var. Biraz hileli olduğunu biliyorum ama pencerede mağazaya sahip olmanın iframe'lere mesaj kullanmaktan daha iyi olacağını düşünüyorum. Düşüncesi olan var mı?? @Vic @trashgenerator?
Sean Malter


10

@Sanchit önerdi gibi güzel bir çözüm ara yazılımdır eğer zaten global AXIOS örneğini tanımlıyorsanız.

Aşağıdaki gibi bir ara katman yazılımı oluşturabilirsiniz:

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;

Ve şu şekilde kullanın:

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

Simgeyi her eylemde ayarlayacaktır, ancak yalnızca jetonu değiştiren eylemleri dinleyebilirsiniz.


aynısını özel bir axios örneğiyle nasıl başarabilirsiniz?
Anatol

3

TypeScript 2.0 için şöyle görünecektir:

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
Oy veriyorsanız, lütfen neden bir yorum ekleyin.
Ogglas

3
Down, yanıtınızda açıklama bulunmadığı ve Javascript yerine TypeScript kullandığından oy kullandı.
Will

2
@Will Nedenini söylediğin için teşekkür ederim. Imao kodu şartname gerektirmez, ancak belirli bir şeyin açıklanmasını istiyorsanız lütfen ne söyleyin. TypeScript gerçekten kullanılır, ancak yazımlar kaldırılırsa, aynı kod sorunsuz bir şekilde ES6'da çalışır.
Ogglas

Şiddetli taraf oluşturma işlemi yapıyorsanız bunun çok kötü olacağını, durumu tüm isteklerle paylaşacağını unutmayın.
Rob Evans

2

Biraz geç olabilir ama en iyi yol axios.interceptorsaşağıdaki gibi kullanmak olduğunu düşünüyorum . İçe aktarma URL'leri proje kurulumunuza göre değişebilir.

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

Kanca ile yapıyorum. Benzer bir sorunla karşılaştım, ama kancalarla tepki-redux kullanıyordum. Arayüzü / mağazadan bilgi alma / gönderme için adanmış kod bir sürü ile benim arayüz kodu (yani, tepki bileşenleri) kadar lard istemedim. Bunun yerine, genel adlara sahip işlevlerin verileri alıp güncellemesini istedim. Benim yolum uygulamanın

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

daha önce adlandırılan store.jsve ekleyen ve store.js'deki olağan tepki-redux ithalatını ekleyen bir modüle dönüştürün . dosya. Daha sonra, uygulama düzeyinde içeri aktardım, daha sonra her zamanki alt öğelerle index.js'ye içe aktardım. Alt bileşenler daha sonra ve kancalarını kullanarak mağazaya erişti .exportconstindex.jsimport {store} from "./store.js"useSelector()useDispatch()

Bileşen olmayan ön uç kodundaki mağazaya erişmek için, benzer içe aktarma (yani import {store} from "../../store.js") kullandım store.getState()ve sonra store.dispatch({*action goes here*})depoya alma ve güncelleme (er, eylem gönderme) işlemlerini gerçekleştirdim.


0

Jetona erişmenin kolay bir yolu, jetonu LocalStorage veya Reac Native ile AsyncStorage'a koymaktır.

React Native projesine sahip bir örnek aşağıda

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

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

Web Window.localStorageiçin AsyncStorage yerine kullanabilirsiniz

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.