javascript - 将 reducer 和操作绑定(bind)到非根组件

标签 javascript reactjs redux react-redux

背景

我在 Angular 1.x 方面有一年半的经验,在 Angular 不适合的项目中转向 React/Redux。我在某处读到过,React 是“基本上所有指令”都来自 Angular,这太棒了,因为我认为指令是 Angular 最强的功能。然而,在 React/Redux 中创建应用程序的心态与 Angular 也非常不同(比如创建数据主干然后表示它的想法,与 Angular 不太集中的方法相比)。有件事我很难理解。

设置

该应用程序是用 Electron 编写的,使用以下内容作为树苗:https://github.com/chentsulin/electron-react-boilerplate

我的根 reducer 看起来像这样:

root: {
  Home: Object, // Basic homepage tab
  Gallery: [ // Gallery tab
    { // A single instance of "photo" object
      filename: String,
      metadata: Object,
      error: Object
    }
  ]
}

图库有打开目录的功能。它扫描用户选择的目录并在那里查找照片,接收文件名数组。然后,它应该将每张照片渲染为一个组件,并且每张照片在使用文件名初始化后,应该启动自己的读取图片元数据并在页面上渲染自己的信息的过程。

我已经可以毫无问题地渲染页面上的所有文件名了。但是,我需要将文件名转换为渲染和处理的照片。这就是我遇到麻烦的地方。

问题

这张照片有一些属性,如上面的内容所示。它还具有一些操作(例如,newupdatedelete 等)。属性和操作需要与组件绑定(bind)。通常,对于页面大小的组件,这是在 JS 文件中完成的,该文件执行所有 connectbindActionCreators 调用。然后这个 JS 文件被包含在 React 路由器中,并以页面的形式呈现。

照片不是页面。它们是可重用的组件,页面上有很多这些组件。如何正确地将照片的所有属性和操作附加到它?

最佳答案

看起来你的模型/ Action / reducer 上的电线可能交叉了。与 Angular 和其他框架不同,您的模型应该是“愚蠢的”,因为它只是数据;您的 GalleryPhoto 对象不应具有方法。相反,您的 View 触发操作,您的 reducer 使用这些操作来更新存储(保存模型),然后读取该存储并将其推回到 View 中。与 MVVM(MVV*?)不同,您的模型(存储状态)不必模仿组件的结构;相反,它只是维护纯数据。因此,拥有 HomeGallery 属性可能没有意义。

让我们像这样重新想象你的 reducer :

const initialState = {
  photos: []
};

export default function reducer(state = initialState, action) {
  switch (action.type) {
    case 'DELETE_PHOTO':
      return { 
        photos: state.photos.filter(photo => photo.filename !== action.payload.filename) 
      };
    // etc.
  }

  return state;
}

现在你的 View 可能是这样的:

import deletePhoto from '../actionCreators/deletePhoto';

function Photo({ filename, onDelete }) {
  return (
    <div>
      <img src={filename}/>
      <button onClick={() => onDelete(filename)}>Delete</button>
    </div>
  );
}

function PhotoGallery({ photos, deletePhoto }) {
  return (
    <div>
    {
      photos.map(photo => <Photo filename={photo.filename} onDelete={deletePhoto}/>);
    }
    </div>
  );
};

const mapStateToProps = state => ({ photos: state.photos });
const mapActionsToProps = { deletePhoto };

export default connect(mapStateToProps, mapActionsToProps)(PhotoGallery);

...那么你的 Action 创建者deletePhoto可能是这样的:

export default function deletePhoto(filename) {
  return { type: 'DELETE_PHOTO', payload: { filename } };
}

建议将您的 reducer 分解为更细粒度的部分,但您可以使用 combineReducers 之类的东西,而不是通过增强模型来实现这一点。 .

我建议你尝试忘记 MVVM 并真正理解 Flux 模式。我并不是说这是一个更好的模式,但如果您尝试在 redux 中使用不同的模式,那么您确实会违背常规。

关于javascript - 将 reducer 和操作绑定(bind)到非根组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39239253/

相关文章:

javascript - redux 形式方法 "PUT"中的 500(内部服务器错误)

javascript - 关于javascript函数调用传递this的解释

javascript - JQuery 根据当前选择的文本输入更改 TR 背景颜色

javascript - 在 Jquery load() 之后设置 div 的高度

reactjs - 为什么这两个 div 的呈现方式不同?

reactjs - 我们如何更改chart.js-2中图例的位置 react

javascript - 如何使用 jest 模拟 react-router-dom 的 BrowserRouter

javascript - 面对类型错误 : Cannot read property 'counter' of undefined when using Redux in React

javascript - React 中的表单提交

javascript - 带有 querySelector 的脚本仅对类有效一次