2017-02-06 36 views
15

mam jeden składnik nadrzędny zwany App.js:ReactJS + Redux: jak skonstruować twórców akcji do każdego komponentu?

... 

render() { 
    return (
    <div> 
     {React.cloneElement(this.props.children, this.props} 
    </div> 
) 
} 

... 

function mapDispatchToProps(dispatch) { 
    return (
    actions: bindActionCreators(actions, 
) 
} 

export default connect(
    ..., 
    mapDispatchToProps 
)(App) 

I rekwizyty będą przekazywane do każdego komponentu. Chciałbym, aby każdy komponent miał swoich twórców akcji, ale jak mogę powiązać wszystkich twórców akcji w jeden, aby twórcy akcji mogli przejść z poziomu App.js? Wszelkie inne sugestie byłyby również doceniane, aby twórcy akcji mieli dostęp do każdego komponentu.

Oto struktura tej pory:

ComponentOne 
..actions.js //action creators 
..ComponentOne.js 
ComponentTwo 
..actions.js //action creators 
..ComponentTwo.js 
App.js 
actions.js//should I compile all the action creators here? 

I każdy actions.js będzie wykonana tak:

let actions = { 
    logSayings() { 
    ... 
    } 
} 

export default actions 

Dziękuję z góry i będzie upvote/zaakceptować odpowiedź.

Redux Konfigurowanie

store.js

import { applyMiddleware, compose, createStore } from 'redux' 
import rootReducer from './reducers/rootReducer' 
import logger from 'redux-logger' 
import thunk from 'redux-thunk' 

let finalCreateStore = compose(
    applyMiddleware(thunk, logger()) 
)(createStore) 

export default function configureStore(initialState = {articles: []}) { 
    return finalCreateStore(rootReducer, initialState) 
} 

actions.js

import { hashHistory } from 'react-router' 
import { browserHistory } from 'react-router'; 

let actions = { 
    updateBar(status) { 
    return { 
     type: 'UPDATE_BAR', 
     indicator: status 
    } 
    } 
} 

export default actions 

homeReducer.js

const homeReducer = function(articles = [], action){ 
    switch(action.type){ 
    case 'UPDATE_BAR': 
     return { 
     indicator: action.indicator, 
     } 

    default: 
     return articles 
    } 
} 

export default homeReducer 

index.js

import React from 'react'; 
import {render} from 'react-dom'; 
import configureStore from '../../redux/store' 
import { Provider } from 'react-redux' 
import { Router, Route, IndexRoute, hashHistory } from 'react-router' 

import App from './components/App' 
import Home from './components/Home/Home' 

let initialState = { 

} 

let store = configureStore(initialState) 

render(
    <div> 
    <Provider store={store}> 
     <Router history={hashHistory}> 
     <Route 
      component={App} 
      path='/' 
     > 
      <IndexRoute component={Home}/> 
     </Route> 
     </Router> 
    </Provider> 
    </div>, 
    document.querySelector('.wrapper') 
) 
+0

Dlaczego chcesz mieć twórców akcji dla wszystkich komponentów potomnych? dlaczego nie możesz scentralizować swoich działań w aplikacji mapDispatchToProps? – Robsonsjre

+0

@Robsonsjre Zrobiłem to, ale doszło do punktu, w którym to było zbyt skupione. Zbyt wielu twórców akcji i zawsze będę musiał przeglądać te nieistotne i znaleźć to, czego potrzebuję. Posiadanie twórców akcji dla danego komponentu pozwala mi szybciej podejrzeć działania twórców akcji. –

Odpowiedz

1

mogę myśleć o dwa podejścia:

  • łącząc actionObjects wszystko w jednym w mapDisatchToProps App.js za
  • Każdy z komponentów może stać się 'kontener' składnik

Przykład 1:

App.js 

import actionObj1 from '../actionComponent1' 

export default connect(
    mapStateToProps, 
    Object.assign({}, actionObj1, actionObj2, actionObj3) 
)(App) 

UPDATE (każdy składnik dziecko staje się pojemnik, wystarczy podłączyć jak na App.js):

Component1.js 

export default connect(
    mapStateToProps, 
    actionObj1) 
)(Component1) 
+0

Czy mógłby Pan rozwinąć kwestię, czy każdy z komponentów stanie się komponentem kontenerowym? Czy mogę połączyć wszystkie w jeden arkusz twórców działań, zamiast importować poszczególne arkusze twórców działań? Czy w tej samej logice jest lepsze podejście? –

+0

Po prostu sprawdzam, czy widziałeś mój poprzedni komentarz. Proszę daj mi znać. –

1

myślę, że coś może chcesz przyjrzeć się zmienia swoją strukturę folderów redux być bardziej modularny. Nie będziesz miał zbyt dużych plików akcji i powinno być łatwiejsze w utrzymaniu niż duże pliki akcji/typu/reduktora, które obejmują wszystkie twoje działania redux.

chciałbym rozdzielić moje Redux działania, typów i reduktory na moduły w następujący sposób:

W moim folderze src będę mieć folder modules. W tym folderze modules będę mieć podfoldery dla różnych typów danych w moim stanie aplikacji. Na przykład folder dla auth, folder dla posts i folder dla comments. Będę też miał index.js.

W każdym folderze będę miał plik actions.js, plik types.js i plik reducer.js.

W każdym pliku action.js będę umieszczał tylko w akcjach, które dotyczą tego typu danych.

Na przykład w pliku mojego folderu postsactions.js będę mieć twórców działania listPosts, getPost itp Struktura mojego twórcy działania jest nieco inny od tego, co można zobaczyć z powodu niestandardowego oprogramowania pośredniczącego, że używam , ale doskonałym przykładem oprogramowania pośredniego, które można wykorzystać jako inspirację lub kopię, jest tutaj: react-redux-universal-hot-example. They use a similar style of putting redux items in modules, chociaż wolą umieszczać wszystkie twórcy akcji, typy i reduktory w połączonych plikach, podczas gdy ja lubię trzymać moje oddzielnie.

import types from './types'; 

export const getPost = id => ({ 
    type: types.LOAD_POST_DETAIL, 
    responseTypes: [types.LOAD_POST_DETAIL_SUCCESS, types.LOAD_POST_DETAIL_FAILURE], 
    promise: client => client.get(`/posts/${id}`), 
}); 

export const listPosts =() => ({ 
    type: types.LIST_POSTS, 
    responseTypes: [types.LIST_POSTS_SUCCESS, types.LIST_POSTS_FAILURE], 
    promise: client => client.get('/posts'), 
}); 

W każdym pliku types.js, będę umieszczać tylko w typach, które odnoszą się do tego typu danych. Na przykład, mój plik types.js może wyglądać następująco:

export default { 
    LOAD_POST_DETAIL: 'LOAD_POST_DETAIL', 
    LOAD_POST_DETAIL_SUCCESS: 'LOAD_POST_DETAIL_SUCCESS', 
    LOAD_POST_DETAIL_FAILURE: 'LOAD_POST_DETAIL_FAILURE', 

    LIST_POSTS: 'LIST_POSTS', 
    LIST_POSTS_SUCCESS: 'LIST_POSTS_SUCCESS', 
    LIST_POSTS_FAILURE: 'LIST_POSTS_FAILURE', 

    UPDATE_POST: 'UPDATE_POST', 
    UPDATE_POST_SUCCESS: 'UPDATE_POST_SUCCESS', 
    UPDATE_POST_FAILURE: 'UPDATE_POST_FAILURE', 
}; 

Mój reduktor będzie miał tylko funkcje redukcyjne specyficzne dla tego typu danych.

Przykładem pliku reducer.js w moim folderze posts:

import { combineReducers } from 'redux'; 
import type { Reducer } from 'redux'; 
import { get, assign } from 'lodash'; 
import types from './types'; 

const all = (
    state = { isFetching: false, data: [] }, 
    action, 
) => { 
    switch (action.type) { 
    case types.LIST_POSTS: 
     return assign({}, state, { isFetching: true }); 
    case types.LIST_POSTS_SUCCESS: 
     return assign({}, state, get(action, 'result.data'), { isFetching: false }); 
    default: return state; 
    } 
}; 

export const reducer = combineReducers({ all }); 

W index.js folderu modules można wyeksportować wszystkich reduktorów (być łączone podczas tworzenia sklepu redux) jak tak :

export { reducer as auth } from './auth/reducer'; 
export { reducer as posts } from './posts/reducer'; 
export { reducer as comments } from './comments/reducer'; 

Kiedy import działanie, byłoby po prostu zrobić coś

import { listPosts } from 'modules/posts/actions'; 

Konfiguracja struktury folderów redux w celu uzyskania bardziej modułowej konstrukcji może zaoszczędzić wiele bólu głowy, ponieważ istnieje wyraźny wzorzec, gdzie będą umieszczane funkcje i gdzie można importować funkcje.

+0

Doceń swoją repsonię Yo. Gdzie znajdą się wszyscy twórcy akcji? –

+0

@JoKo, zaktualizowałem swoją odpowiedź, aby dać przykład niektórych twórców akcji w moim pliku actions.js. Zauważ, że moi twórcy akcji są nieco różni się od tego, co normalnie widzisz, ale to dlatego, że używam niestandardowego oprogramowania pośredniego, które jest oparte na oprogramowaniu pośrednim, ale jest dość specyficzne dla moich implementacji, więc nie różni się znacząco funkcjonalnie od ten, który połączyłem. Zamieszczam także uwagi dotyczące oprogramowania pośredniego obietnic/klientów i zamieszczam link do przykładowego oprogramowania pośredniego, z którego można czerpać inspirację, oraz połączony przykład modularnej separacji elementów sklepu. –

6

Oto, jak zwykle strukturę mojej aplikacji reagowania/redux.

Prowadzę akcje poza kontenerami komponentów &. Zwykle staram się nazwać moje pliki akcji specyficzne dla obszarów aplikacji, które buduję. na przykład UsersActions, ProductActions, OrdersActions, CheeseActions działa zbyt ...

App 
    actions 
    CheeseActions.js 
    ... 
    components 
    CheeseBox.js 
    containers 
    CheeseApp.js 
    ... 

Przykład Container - Niech pojemnik uchwyt działania. (Trochę jak kontroler.)

// import the actions that this container needs to do it's job. 
import { makeCheese, sellCheese } from '../actions/CheeseActions' 
import CheeseBox from '../components/CheeseBox' 

class CheeseApp extends Component { 

    // Let the container handle the actions 
    onPurchasePressed(kind) { 
    dispatch(sellCheese(kind)) 
    } 

    // More actions... 

    render() { 
    return(
     <CheeseBox onPurchase={this.onPurchasePressed.bind(this)} /> 
    ) 
    } 

} 

... 

export default connect(mapStateToProps)(CheeseApp) 

Przykład Component - Jedziemy do niech pojemnik obsługiwać funkcję użyciu this.props.onPurchase ('Cheddar').

// Cheesebox is dumb, keep him that way. 
export default class CheeseBox extends Component { 

    static propTypes = { 
    onPurchase: PropTypes.func.isRequired, 
    } 

    render() { 
    const { onPurchase } = this.props 
    return(
     <p>Hi, I love cheese.</p> 
     <a onClick={() => onPurchase('Cheddar')} />Buy Now!</a> 
    ) 
    } 

} 

Mam nadzieję, że jest to pomocne. Daj mi znać, jeśli masz jakieś pytania.

5

Jednym ze sposobów, aby to zrobić jedzie modułowy charakter mądry. w ten sposób kod będzie czystsze i czytelny.

App 
    action/ 
    component1Actions.js 
    ... 
    componentnActions.js 
    actionTypes.js 
    components/ 
    Component1.js 
    ... 
    Componentn.js 
    container/ 
    Component1.js 
    ... 
    Componentn.js 
    reducers/ 
    component1Reducer.js 
    ... 
    componentnReducer.js 

struktura pokazana powyżej jest to, co większość deweloperów mam napotkanych wykorzystali (wolę to podejście). ma to sens, ponieważ oddzielają każdy plik na podstawie charakteru tego pliku. To podejście jest odpowiednie dla małych i średnich projektów, w których nie ma zbyt wielu oddzielnych plików.

W dużych aplikacjach często trudno jest utrzymać kod.

Kolejna szkoła myślenia idzie domain-wise

app/ 
    ... 
    App.js 
    reducers.js 
    routes.js 
    product/ 
    Product.js 
    ProductContainer.js 
    productReducer.js 
    ... 
    user/ 
    User.js 
    UserContainer.js 
    UserActions.js 
    userReducer.js 
    ... 

Korzyść z tego jest to, że możemy oddzielić pliki na podstawie swojej kategorii. Dla np. aplikacja wymaga składnika użytkownika. Byłoby łatwiej, gdybyśmy przechowywali wszystkie pliki związane z tą domeną w jednym katalogu. W ten sposób struktura aplikacji będzie czystsza w dużych aplikacjach.

Oba mają korzyści. Pod koniec dnia struktura nie ma znaczenia. To bardziej osobisty wybór.

+0

Naprawdę doceniam wgląd! Próbuję oddzielić pliki na podstawie ich domeny i bieżącej konfiguracji, mam problem z tym. Zaktualizowałem oryginalny post z moją obecną konfiguracją redux. Reduktory są rozdzielone, ale działania nie są. Czy możesz pokazać, jak zmienić konfigurację, aby działała w oparciu o jej domenę? Z góry dziękuję! –

+0

Sprawdź to repozys https://github.com/koshuang/react-redux-starter-kit. To może zaoferować lepsze wyjaśnienie tej struktury. – DroidNoob