制作"编辑细节"的正确/首选方式是什么? React中的组件?

时间:2016-01-09 13:19:32

标签: javascript reactjs

我正在处理一个数据模型'是一个集合,例如,一群人。它们被打包到React组件中并在页面上平铺。基本上它就像:

class App extends React.Component {
    constructor() {
        super();
        this.state = { people: /* some data */ };
    }

    render () {
        return (
            <div>
                {this.state.people.map((person) =>
                    <People data={person}></People>)}
            </div>);
    }
}

现在我想为<People>组件中的每个条目附加一个编辑部分,允许用户更新名称,年龄......特定条目的各种信息。

由于React不支持在组件内部改变道具,我搜索并发现添加回调作为道具可以解决将数据传递给父级的问题。但由于有许多字段需要更新,因此会有许多回调,例如onNameChangedonEmailChanged ...这可能非常难看(随着字段数量的不断增加,也越来越冗长)。

那么正确的方法是什么?

1 个答案:

答案 0 :(得分:1)

诚实? 最佳方式是Flux (在一分钟内回到那里)。

如果您开始以道具的形式向下传递数据,然后将其传回以使用回调进行编辑,那么您将打破React构建的单向数据流

然而,并非所有项目都需要写入理想标准,并且可以在没有Flux的情况下构建它(有时甚至可能是正确的解决方案)。

没有助焊剂

通过传递单个edit函数作为道具,您可以在不需要大量回调的情况下实现此功能。此函数应采用id和新的person对象,然后在运行时更新父组件内的状态。这是一个例子。

editPerson(id, editedPerson) {
  const people = this.state.people;
  const newFragment = { [id]: editedPerson };

  // create a new list of people, with the updated person in
  this.setState({
    people: Object.assign([], people, newFragment)
  });
},
render() {
  // ...
  {this.state.people.map((person, index) => {
    const edit = this.editPerson.bind(this, index);

    return (
      <People data={person} edit={edit}></People>
    );
  })}
  // ...
}

然后在您的人员组件中,每当您对此人进行更改时,只需将该人员通过回调传递回父状态。

但是,如果您通过应用程序可视化数据流,那么您现在已经创建了一个类似于此的循环。

 App
  ^
  |
  v
Person

找出应用程序中的数据来源不再是微不足道的(在如此小的应用程序中它仍然非常简单,但显然它越大越难以辨别。

使用Flux

最初,Facebook开发人员使用单向数据流编写了React应用程序,他们发现它很好。然而,需要数据上升到树上,这导致了危机。我们的数据流如何是单向的并仍然返回到树的顶部?在第七天,他们创建了Flux(1),看到它非常好。

Flux允许您将更改描述为操作并将其从组件传递到存储(自包含状态框),这些存储了解如何根据操作操纵其状态。然后,商店会告诉所有关心它的组件已经发生了变化,此时组件可以获取要渲染的新数据。

您可以重新获得单向数据流,其架构看起来像这样。

 App <---- [Stores]
  |            ^
  v            |
Person --> Dispatcher

店铺

您可能希望创建一个人工商店来跟踪您的人员列表,而不是将您的状态保留在<App />组件中。

也许它看起来像这样。

// stores/people-store.js
const people = [];

export function getPeople() {
  return people;
}
function editPerson(id, person) {
  // ...
}
function addPerson(person) {
  // ...
}
function removePerson(id) {
  // ...
}

现在,我们可以导出这些函数并让我们的组件直接调用它们,但这很糟糕,因为这意味着我们的组件必须知道商店的设计,我们希望将它们视为愚蠢的可能的。

操作

相反,我们的组件创建了简单,可序列化的操作,我们的商店可以理解。以下是一些例子:

// remove person with id 53
{ type: 'PEOPLE_REMOVE', payload: 53 }

// create a new person called John Foo
{ type: 'PEOPLE_ADD', payload: { name: 'John Foo' } }

// edit person 13
{
  type: 'PEOPLE_EDIT',
  payload: {
    id: 13,
    person: { name: 'Unlucky Bill' }
  }
}

这些操作不必具有这些特定的密钥,它们甚至不必是对象,这只是来自Flux Standard Actions的惯例。

分派器

现在,我们告诉我们的商店,当他们到达时如何处理这些行为。

 // stores/people-store.js
 // ...
 dispatcher.register(function(action) {
   switch(action.type) {
     case 'PEOPLE_REMOVE':
       removePerson(action.payload);
     case 'PEOPLE_ADD':
       addPerson(action.payload);
     case 'PEOPLE_EDIT':
       editPerson(action.payload.id, action.payload.person);
   }
 });

呼。到目前为止,很多工作都在那里。

现在我们可以开始从我们的组件中发送这些操作。

 // components/people.js
 // ...
 onEdit(editedPerson) {
   dispatcher.dispatch({
     type: 'PEOPLE_EDIT',
     payload: {
       id: this.props.id,
       person: editedPerson
     }
   });
 }
 onRemove() {
   dispatcher.dispatch({
     type: 'PEOPLE_REMOVE',
     payload: this.props.id
   });
 }
 // ...

编辑此人时,请调用this.onEdit方法,然后将相应的操作发送到您的商店。移除一个人同样如此。通常情况下,您会将此内容移动到动作创建者中,但这又是另一个主题。

好的,终于到了某个地方!现在,我们的组件可以创建更新商店中数据的操作。我们如何将这些数据反馈到我们的组件中?

最初,它非常简单。我们可以要求商店在我们的顶级组件中,只需要询问数据。

// components/app.js
import { getPeople } from './stores/people-store';
// ...
constructor() {
  super();
  this.state = { people: getPeople() };
}

我们可以用完全相同的方式传递这些数据,但是当数据发生变化时会发生什么?

Flux的官方立场基本上是&#34;不是我们的问题&#34;。 Their examples使用Node的Event Emitter类允许商店接受商店更新时调用的回调函数。

这允许您编写看起来像这样的代码:

componentWillMount() {
  peopleStore.addListener(this.peopleUpdated);
},
componentWillUnmount() {
  peopleStore.removeListener(this.peopleUpdated);
},
peopleUpdated() {
  this.setState({ people: getPeople() });
}

真的,这个球在你的球场上。还有许多其他策略可以将数据恢复到您的程序中。 Reflux自动为您创建listen方法,Redux允许您以声明方式指定哪些组件接收商店的哪些部分作为props,然后它处理更新。在Flux上花足够的时间,你会找到一个偏好。

现在,您可能正在思考,blimey - 这似乎需要付出很多努力才能将编辑功能添加到组件中;你是对的,是的!

对于小型应用程序,您可能不需要Flux。

当然有很多好处,但额外的复杂性并不总是有道理的。随着您的应用程序的增长,您会发现如果您将其应用起来,那么管理,维护和调试将会更加容易。

诀窍在于知道什么时候使用Flux架构是合适的,并且希望在时机成熟时,这个过长而漫无边际的答案将为您解决问题。

  1. 这实际上并非如此。