我正在一个页面上,其“数据模型”是一个集合,例如,一群人。它们被打包到React Components中并在页面上平铺。本质上是这样的:

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不支持组件内部的props变异,因此我搜索并发现将回调添加为props可以解决将数据传递给parent的问题。但是由于有许多要更新的字段,因此会有许多回调,例如onNameChangedonEmailChanged ...可能非常难看(随着字段数量的增长,冗长程度也越来越高)。

那么正确的方法是什么呢?

最佳答案

老实说最好的方法是助焊剂(在一分钟内即可返回)。

如果您开始以道具的形式将数据传递到树上,然后再传递回去使用回调进行编辑,那么您将打破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


确定应用程序中数据的来源不再是轻而易举的事(在如此小的应用程序中,数据仍然很简单,但是显然,数据越大,越难分辨。

有助焊剂

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

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

您将使用如下所示的体系结构重新获得单向数据流。

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


专卖店

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

也许看起来像这样。

// 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);
   }
 });


ew到目前为止,还有很多工作要做。

现在,我们可以开始从组件中调度这些操作。

 // 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的官方立场基本上是“不是我们的问题”。 Their examples使用Node的Event Emitter类允许商店接受在商店更新时调用的回调函数。

这使您可以编写看起来像这样的代码:

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


真的,这球在您的球场上。还有许多其他策略可以将数据重新存储到程序中。 Reflux自动为您创建listen方法,Redux允许您声明性地指定哪些组件将商品作为道具接收商店的哪些部分,然后进行更新。花足够的时间在Flux上,您会发现自己的喜好。

现在,您可能在想,Blimey –似乎只是为了向组件添加编辑功能而付出了很多努力。你是对的,是的!

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

当然,这样做有很多好处,但并非总是保证额外的复杂性。随着应用程序的增长,您会发现,如果对它进行了改进,则将更易于管理,维护和调试。

诀窍是要知道何时适合使用Flux架构,并希望何时到来,这个漫长而漫不经心的答案将为您解决问题。




这不是真的。

09-11 19:08
查看更多