Javascript ReactJS+;Redux:如何将动作创建者组织到每个组件?
我有一个父组件叫做Javascript ReactJS+;Redux:如何将动作创建者组织到每个组件?,javascript,reactjs,redux,react-jsx,Javascript,Reactjs,Redux,React Jsx,我有一个父组件叫做App.js: ... render() { return ( <div> {React.cloneElement(this.props.children, this.props} </div> ) } ... function mapDispatchToProps(dispatch) { return ( actions: bindActionCreators(actions, ) } ex
App.js
:
...
render() {
return (
<div>
{React.cloneElement(this.props.children, this.props}
</div>
)
}
...
function mapDispatchToProps(dispatch) {
return (
actions: bindActionCreators(actions,
)
}
export default connect(
...,
mapDispatchToProps
)(App)
每个actions.js
都会这样做:
let actions = {
logSayings() {
...
}
}
export default actions
export { reducer as auth } from './auth/reducer';
export { reducer as posts } from './posts/reducer';
export { reducer as comments } from './comments/reducer';
提前感谢您,我们将投票/接受答案
REDUX设置
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')
)
从“React”导入React;
从'react dom'导入{render};
从“../../redux/store”导入configureStore
从“react redux”导入{Provider}
从“react Router”导入{Router,Route,IndexRoute,hashHistory}
从“./components/App”导入应用程序
从“./components/Home/Home”导入Home
让initialState={
}
let store=configureStore(initialState)
渲染(
,
document.querySelector(“.wrapper”)
)
我可以考虑两种方法:
- 在App.js的mapDisatchToProps中将actionObjects合并在一起
- 每个组件都可以成为“容器”组件
App.js
import actionObj1 from '../actionComponent1'
export default connect(
mapStateToProps,
Object.assign({}, actionObj1, actionObj2, actionObj3)
)(App)
更新(每个子组件都成为容器,就像在App.js上一样连接):
我认为您可能希望看到的是将redux文件夹结构更改为更加模块化。您不会有臃肿的操作文件,而且应该比包含所有redux操作的大型操作/类型/缩减器文件更易于维护 我喜欢按以下方式将我的redux操作、类型和还原程序划分为模块: 在我的
src
文件夹中,我将有一个modules
文件夹。在这个modules
文件夹中,我将为我的应用程序状态中的不同类型的数据创建子文件夹。例如,一个用于auth
的文件夹,一个用于posts
的文件夹,以及一个用于评论的文件夹。我还将有一个index.js
在每个文件夹中,我将有一个actions.js
文件、一个types.js
文件和一个reducer.js
文件
在每个action.js
文件中,我将只放置与该类型数据相关的操作
例如,在我的posts
文件夹的actions.js
文件中,我将有action creatorslistPosts
,getPost
,等等。我的action creator的结构与您可能看到的略有不同,因为我使用的是自定义中间件,但这里有一个很好的中间件示例,您可以将其作为灵感或复制品:,虽然他们更喜欢把所有的动作创建者、类型和还原者放在组合文件中,而我喜欢把我的分开
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'),
});
在每个types.js
文件中,我将只放置与该类型数据相关的类型。
例如,我的types.js
文件可能如下所示:
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',
};
我的reducer将只具有特定于该类型数据的reducer函数
我的posts
文件夹中的reducer.js
文件示例:
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 });
在modules
文件夹的index.js
中,您可以导出所有还原程序(在创建redux存储时合并),如下所示:
当您导入一个动作时,您只需执行如下操作
import { listPosts } from 'modules/posts/actions';
设置redux文件夹结构,使其具有更模块化的设计,可以为您省去很多麻烦,因为函数的放置位置和导入位置都有明确的模式。以下是我通常如何构建react/redux应用程序的
我将操作保持在组件和容器之外。我通常会尝试将我的动作文件命名为我正在构建的应用程序的特定区域。e、 用户操作、产品操作、订单操作、奶酪操作也有效
App
actions
CheeseActions.js
...
components
CheeseBox.js
containers
CheeseApp.js
...
示例容器-让容器处理操作。(有点像控制器。)
//导入此容器执行其工作所需的操作。
从“../actions/CheeseActions”导入{makeCheese,sellCheese}
从“../components/CheeseBox”导入CheeseBox
类CheeseApp扩展组件{
//让容器处理这些操作
onPurchasePressed(种类){
调度(货物(种类))
}
//更多行动。。。
render(){
返回(
)
}
}
...
导出默认连接(MapStateTops)(CheeseApp)
示例组件-我们将让容器处理函数,
使用这个.props.onPurchase('Cheddar')
//奶酪盒很笨,让他保持这种状态。
导出默认类CheeseBox扩展组件{
静态类型={
onPurchase:PropTypes.func.isRequired,
}
render(){
const{onPurchase}=this.props
返回(
嗨,我喜欢奶酪
onPurchase('Cheddar')}/>立即购买!
)
}
}
希望这是有帮助的。如果您有任何问题,请告诉我。只是想分享一篇我认为可能与此相关的博客文章
但总的来说,我同意Breet的回答,也不同意博客的观点(:实现这一点的一种方法是采用模块化的自然方式。这样代码将更清晰、可读
App
action/
component1Actions.js
...
componentnActions.js
actionTypes.js
components/
Component1.js
...
Componentn.js
container/
Component1.js
...
Componentn.js
reducers/
component1Reducer.js
...
componentnReducer.js
上面显示的结构是我遇到的大多数开发人员都使用过的(我更喜欢这种方法)。这是有意义的,因为我们根据文件的性质将每个文件分开。这种方法适用于没有那么多单独文件的中小型项目
在大型应用程序中,维护代码通常变得很困难
另一个学派正在兴起
这样做的好处是,我们根据其域来分离文件。例如,一个应用程序需要一个用户组件。如果我们将与该域相关的所有文件保存在一个目录下,会更容易。这将使大型应用程序中的应用程序结构更干净
两者都有好处。归根结底,结构并不重要。它更多的是个人选择。为什么你想在所有子组件上都有动作创建者?为什么你不能将动作集中在应用程序的mapDispatchToProps上?@Robsonsjre I'd
App
actions
CheeseActions.js
...
components
CheeseBox.js
containers
CheeseApp.js
...
// 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)
// 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>
)
}
}
App
action/
component1Actions.js
...
componentnActions.js
actionTypes.js
components/
Component1.js
...
Componentn.js
container/
Component1.js
...
Componentn.js
reducers/
component1Reducer.js
...
componentnReducer.js
app/
...
App.js
reducers.js
routes.js
product/
Product.js
ProductContainer.js
productReducer.js
...
user/
User.js
UserContainer.js
UserActions.js
userReducer.js
...