Custom Redux Altyapısı Oluşturalım

React evrenine yeni adapte olmaya çalışan birinin karşısına kesinlikle Redux adlı arkadaşı çıkacaktır. Redux altyapısını ileri düzeyde anlamak ve kavramak amaçlı bugün kendi Redux altyapımızı oluşturacağız. Bu sayede kütüphane kullanıp, aslında kütüphanenin ne yaptığını bilmeyenlerden olmayacağız :)

Uygulamamızın içeriği çok basit olacak (Counter). Hedefimiz kendi Redux altyapımız ile global state üzerinde tutulan bir rakamın değerini arttırmak ve azaltmak olacak.

Redux Store

Redux Store birkaç şeyden sorumlu olabiliyor. Öncelikle, uygulamanın şuanki durumunu içeriyor ve çağıracağımız reducerlar ile durumu güncelleme imkanı veriyor. Redux'da reducer tetiklemenin yöntemi 'dispatch()' fonksiyonudur. Ayrıyetten bu tetiklemeleri bilecek olan dinleyicilere ihtiyacımız olacak. Redux'da yeni bir dinleyici kaydetmek için 'subscribe()' fonksiyonunu kullanarak abone olmanız gerekiyor. Store'da yeni bir güncelleme olduğunda yani yeni bir durum oluşturulduğunda 'getState()' ile son durumu alabiliriz.

Aşağıda store yapısına göz atabilirsiniz.

let state;
  let listeners = [];

  const getState = () => state;

  const dispatch = action => {
    state = rootReducer(state, action);
    listeners.forEach(listener => listener(state));
  };

  const subscribe = listener => {
    listeners.push(listener);
  };

  dispatch({});

  return { getState, dispatch, subscribe };
};

export { createStore };

Redux Combine Reducers

Store, yalnızca bir reducer fonksiyonunun geçmesine izin verir. Daha büyük uygulamalarda, daha fazla reducer ve daha fazla kontrol mekanizmasına ihtiyacınız olacaktır. 'combineReducers()' fonksiyonu ile birden fazla reducer'ın bulunduğu tek bir nesneye çevirebilirsiniz. 'combineReducers()', sadece reducer'ları çağırır ve yeni durumları nesnelere kaydeder.

const combineReducers = reducers => {
  const nextState = {};
  const reducerFunctions = {};
  const reducersKeys = Object.keys(reducers);
  reducersKeys.forEach(reducerKey => {
    if (typeof reducers[reducerKey] === "function") {
      reducerFunctions[reducerKey] = reducers[reducerKey];
    }
  });
  const reducerFunctionsKeys = Object.keys(reducerFunctions);

  return (state = {}, action) => {
    reducerFunctionsKeys.forEach(reducerKey => {
      const reducer = reducerFunctions[reducerKey];
      nextState[reducerKey] = reducer(state[reducerKey], action);
    });

    return nextState;
  };
};

Redux Provider

Redux, uygulamadaki durumu global olarak paylaşmak için özel bir bileşen kullanır. Bu bileşene 'Provider' diyoruz (Kapsayıcı).  

const ReduxContext = React.createContext("redux");

const Provider = ({ store, children }) => (
  <ReduxContext.Provider value={store}>{children}</ReduxContext.Provider>
);

Redux Connect

Kısaca High Order Component (HOC) diyebiliriz. Bu HOC, componentinizi sarar ve Redux tarafından gelen nesnelerin son durumları (mapStateToProps) ve bu nesneleri güncelleyebileceğimiz reducerlar'ı (mapDispatchToProps) barındırarak componentimizi Redux'ın bir parçası haline getirir. Bu sayede bağladığımız component, Redux'da olup bitenden haberdar olmuş olur.

const connect = (mapStateToProps, mapDispatchToProps) => Component => {
  class Connect extends React.Component {
    constructor(props) {
      super(props);

      this.state = props.store.getState();
    }

    componentDidMount() {
      this.props.store.subscribe(state => {
        this.setState(state);
      });
    }

    render() {
      const { store } = this.props;

      return (
        <Component
          {...this.props}
          {...mapStateToProps(store.getState())}
          {...mapDispatchToProps(store.dispatch)}
        />
      );
    }
  }

  return props => (
    <ReduxContext.Consumer>
      {store => <Connect {...props} store={store} />}
    </ReduxContext.Consumer>
  );
};

Uygulamanın son haline aşağıdaki linkten erişebilirsiniz.

https://github.com/emreyalvac/custom-redux

İyi çalışmalar dilerim.