如何在React中自由地使用具有setter的pojo作为状态

时间:2014-11-22 00:26:54

标签: reactjs

击中一个路障,我正在寻求帮助。我开始从我的React组件中移出更多的“状态”pojo,因为例如我不确定现在应该如何利用我的pojo的setter方法(可能需要setter方法来验证等)。我现在发现自己要么违反React docs的警告,要么永远不要直接触摸this.state,要么将大部分代码除了渲染 - 包括状态 - 在React组件之外移动到我自己的js变量/对象中(并保持对渲染对象的引用然后使用forceUpdate()重新渲染)。什么是自由使用我想要的普通旧js数据/模型对象的推荐方法,包括使用setter方法?

这个准确的示例,我想要一个表单支持数据对象,展示了我面临的这种差异:http://jsfiddle.net/jL0rf0ed/http://jsfiddle.net/rzuswg9x/。还粘贴了下面第一个代码。

至少,我有这个具体的问题:在this.state的自定义/手动更新之后,会有一个this.setState(this.state)行,它来自React组件和一个组件。 forceUpdate()行可能来自React组件外部,与标准this.setState({someKey:someValue})一样快速正确地工作?

感谢。

//props: dataObj, handleInputChange
test.ComponentA = React.createClass({
    getInitialState: function() {
        return {
            age: 21,
            email: 'a@b.com', //TODO make members private
            setEmail: function(val) { //TODO utilize this
                this.email = val;
                if(val.indexOf('@') == -1) {
                    //TODO set or report an error
                }
            }
        }       
    },
    handleInputChange: function(e) {
        this.state[e.target.name]=e.target.value; //defying the "NEVER touch this.state" warning (but it appears to work fine)!
        this.setState(this.state); //and then this strange line
    },
    render: function() {
        return (
            <div>
                <input type='text' name='age' onChange={this.handleInputChange} value={this.state.age}></input>
                <input type='text' name='email' onChange={this.handleInputChange} value={this.state.email}></input>
                <div>{JSON.stringify(this.state)}</div>
            </div>
        );
    }
});

React.render(<test.ComponentA />, document.body);

2 个答案:

答案 0 :(得分:1)

对于粘贴代码段中的代码示例,您可以执行以下操作。

handleInputChange: function(e) {
  var updates = {};
  updates[e.target.name] = e.target.value;
  this.setState(updates);
},

在第二个示例中,您不应该从组件本身外部调用forceUpdatesetState。正确的方法是将状态包含在任何呈现组件的内容中,并将数据作为props传递。

通常这意味着你有一个包装器组件。

var RootComponent = React.createClass({
  getInitialState: ...

  onInputChange: function() {
    this.setState({yourKey: yourValue});
  },

  render: function() {
    return <SubComponent yourKey={this.state.yourKey} onInputChange={this.onInputChange} />;
  }
};

在您的情况下,我建议您创建此包装器组件。另一种解决方案是将相同的组件重新呈现到同一个DOM节点中。

test.handleInputChange = function(e) {
  // update test.formPojo1 here
  React.render(<test.ComponentA dataObj={test.formPojo1} handleInputChange={...} />);
}

因为它是相同的组件类和DOM节点,所以React会将其视为更新。

答案 1 :(得分:-1)

商店

Facebook在Store架构中使用Flux的概念。

商店是一个非常有针对性的POJO。而且我发现使用Store隐喻而不使用整个Flux非常简单。

样品商店

这是我从我们的一个生产React应用程序中提取的商店:

ChatMessageStore = {
  chatMessages: [],

  callbacks: [],

  getAll: function() {
    return this.chatMessages;
  },

  init: function() {
    this.chatMessages = window.chat_messages.slice();
    return this.emitChange();
  },

  create: function(message) {
    this.chatMessages.push(message);
    return this.emitChange();
  },

  emitChange: function() {
    return this.callbacks.forEach(callback, function() {
      return callback();
    });
  },

  addChangeListener: function(callback) {
    return this.callbacks.push(callback);
  },

  removeChangeListener: function(callback) {
    return this.callbacks = _.without(this.callbacks, callback);
  }
};

将其连接到React组件

在您的组件中,您现在可以在商店中查询其数据:

var Chat = React.createClass({
  componentWillMount: function() {
    return ChatMessageStore.addChangeListener(this._onChange);
  },

  componentWillUnmount: function() {
    return ChatMessageStore.removeChangeListener(this._onChange);
  },

  getInitialState: function() {
    return this.getMessageState();
  },

  getMessageState: function() {
    return {
      messages: ChatMessageStore.getAll()
    };
  }
});

组件向Store注册回调,该回调在每次更改时触发,更新组件并遵守“不要修改状态”的规则。