2016-03-02 58 views
3

我有一个reactJs应用程序,现在我正在学习Redux以将其用作Flux实现。Redux:只有同步调用允许从reducer功能?

我创建了一个商店,我已经创建了我的第一个减速功能,但现在我有一些问题,来我的心,请帮我明白了。

正如你可以看到我有一个名为“FIND_PRODUCTS”这基本上是从后端服务中获取数据的作用。为了调用这个后端服务,我基本上使用了一个异步的ajax调用,所以基本上我面临的问题是,在我的后端调用完成之前,状态是从reducer函数返回的,因此状态没有正确更新,并且用户该商店正在获取不正确的数据。如果我切换到同步调用,这个问题就解决了,但是,我得到的第一个警告是应该避免同步调用,因为它可能会降低用户的体验(性能)。

所以我的问题,可我们只从同步减速功能获取数据? 提取数据是否应该在reducer函数中发生,或者有另一种方法可以做到这一点?如果是这样,那是什么?

是否具有单一的对象树与大型应用程序维护国家尺度很好的终极版这种模式?如果我有1000个动作,那么我的减速器功能中的开关就会很大!我们如何避免这种情况?

谢谢!

const initialState = { 
availableLocales: [{text: 'En'}, {text: 'Es'}, {text: 'Fr'}], 
selectedLocale: 'En', 
translations: i18n.getTranslations(), 
products: [] 
}; 


const reducer = (state = initialState, action = {type: 'NONE'})=> { 

//To make the reducer a pure function 
deepFreeze(state); 
deepFreeze(action); 
switch (action.type) { 
    case 'SWITCH_LOCALE': 
     let newState = Object.assign({}, state, { 
      selectedLocale: action.locale, 
      translations: i18n.getTranslations(action.locale) 
     }); 
     return newState; 
    case 'FIND_PRODUCTS': 
     let newState = Object.assign({}, state, { 
      products:ProductHelper().findProductsByProductType(action.productType) 
     }); 
     return newState; 

    default: 
     return state 
} 
return state; 
} 

// Create a Redux store holding the state of your app. 
// Its API is { subscribe, dispatch, getState }. 
const store = createStore(reducer); 

// You can subscribe to the updates manually, or use bindings to your view layer. 
store.subscribe(() => 
    console.log(store.getState()) 
); 

export default store; 
+0

组件不能调用componentWillMount方法的findProduct异步函数吗? – Raulucco

+0

当然,但是我们需要什么店?我认为这一切的关键是将国家从零部件转移到商店.. – fgonzalez

回答

5

考虑一下:

创建actions.js文件和导出操作这样的功能:

import * as types from '../constants/action_types'; 
import * as api from '../utils/api' 

export function something1(someId){ 

    return (dispatch) => { 

     dispatch({type: `${types.SOMETHING1}_PENDING`}); 

     api.getSomething(someId) 

      .then((res) => { 
       dispatch({ 
        type: `${types.SOMETHING1}_SUCCEEDED`, 
        somethings: res.body 
       }); 

      .catch((err) => { 

       dispatch({ 
        type: `${types.SOMETHING1}_FAILED`, 
        errors: err.body 
       }) 

      }); 
    } 
} 

export function something2(someOtherId){ 

    return (dispatch) => { 

     dispatch({type: `${types.SOMETHING2}_PENDING`}); 

     api.getSomething2(someOtherId) 

      .then((res) => { 
       dispatch({ 
        type: `${types.SOMETHING2}_SUCCEEDED`, 
        otherThings: res.body 
       }); 

      .catch((err) => { 

       dispatch({ 
        type: `${types.SOMETHING2}_FAILED`, 
        errors: err.body 
       }) 

      }); 
    } 
} 

然后,状态时,你有数据

下一个单独的文件分开你的减速,并创建一个文件导出所有这些只改变 这样的减速/ index.js:

export { default as reducer1 } from './reducer1'; 
export { default as reducer2 } from './reducer2'; 
export { default as reducer3 } from './reducer3'; 
export { default as reducer4 } from './reducer4'; 

然后配置你的店是这样的:

configure_store.js

import { createStore, combineReducers, applyMiddleware } from 'redux'; 
import thunk from 'redux-thunk'; 
import * as reducers from '../reducers'; 

const rootReducer = combineReducers(reducers); 
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore); 

export default function configureStore(initialState) { 
    return createStoreWithMiddleware(rootReducer, initialState); 
} 

最后添加到您的根:

import configureStore from '../store/configure_store'; 

const store = configureStore(); 

class Root extends Component { 

    render() { 
     return (
      ... 
      <Provider store={ store } > 
      ... 
      </Provider> 
     ); 
    } 
} 

export default Root; 
3

首先,你不能在reducer中获取数据,因为它需要通过redux定义来纯化。您应该创建动作创建器,它将异步获取数据并将其传递给Reducer。行动可能不纯。

在这里,你可以阅读更多http://redux.js.org/docs/advanced/AsyncActions.html

您也可以使用中间件像redux-thunk对此进行简化。 https://github.com/gaearon/redux-thunk


至于第二个问题,你可以在你的应用程序超过一个减速。而不是将它们与combineReducers(...)函数结合使用http://redux.js.org/docs/basics/Reducers.html

1

不应该在Reducer中使用ProductHelper()来请求数据。

相反,你应该用行动创造者派遣,从您的API请求数据的操作。您的API中间件会返回一个承诺,在完成时将分派一个动作意图与有效负载,以使reducer消耗并返回下一个状态。

我建议你看看Redux ThunkRedux API middleware

2

正如redux documentation说,减速应该是纯功能,所以它不应该做的Ajax请求。

更好的方法是使用redux-thunk中间件,它允许您在一个操作中多次调用dispatch

所以,在你的榜样,你做这样的事情:

// definition of action creator 
function loadProducts(productType) { 
    return {type: 'FIND_PRODUCTS', productType: productType} 
} 

... 
// calling dispatch of your action 
dispatch(loadProducts(productType)); 

但随着终极版 - 咚你的行动的创建者会是这样的:

function loadProducts(productType) { 
    return function(dispatch){ 
    dispatch({type: 'FIND_PRODUCT_STARTED'}); 
    // I don'h know how findProductsByProductType works, but I assume it returns Promise 
    ProductHelper().findProductsByProductType(productType).then(function(products){ 
     dispatch({type: 'FIND_PRODUCT_DONE', products: products}); 
    }); 
    } 
} 

而且你的减速将成为纯函数:

... 
case 'FIND_PRODUCTS_DONE': 
    let newState = Object.assign({}, state, { 
     products: action.products, 
    }); 
    return newState; 
... 

在这种情况下,您还可以处理加载状态,即设置loading当你的状态为真时action.typeFIND_PRODUCT_STARTED

在我的例子中,我假设findProductsByProductType返回Promise。在这种情况下,你甚至可以使用redux-promise-middleware没有终极版,形实转换,它会做所有的工作对您:

function loadProducts(productType) { 
    return { 
    type: 'FIND_PRODUCT', 
    payload: { 
     promise: ProductHelper().findProductsByProductType(productType) 
    } 
    } 
}