如果不鼓励使用forceUpdate(),组件应如何对模型中的事件进行更改?

1in*_*ion 3 javascript reactjs

我在我的应用程序中的几个组件中使用以下模式.我注意到很多人不鼓励使用forceUpdate(),有些人甚至称之为黑客攻击.那么如何不使用它呢?

// user.js

export default class User extends EventEmitter {
    constructor(args) {
        super();
        this.id = args.id;
        this.isActivated = args.isActivated || false;
    }
    activate() {
        this.isActivated = true;
        this.emit('change');
    }
}

// UserView.jsx

export default class UserView extends React.Component {
    componentDidMount() {
        this.props.user.on('change', this.onUserUpdate);
    }
    onUserUpdate() {
        this.forceUpdate();
    }
    render (
        var user = this.props.user;
        return (
            <div>
                <span>User {user.isActivated ? 'is' : 'is not'} activated.</span>
                <button onClick={user.activate()}>Activate</button>
            </div>
        );
    );
}

// app.js

var user = new User({ id: 123 });
ReactDOM.render(<UserView user={user} />, container);
Run Code Online (Sandbox Code Playgroud)

Dan*_*nce 6

当道具或状态发生变化时,React会自动渲染组件.

如果您的模型具有更改属性,则应将其保持在组件的本地状态.

componentWillMount() {
  this.setState({
    user: this.props.user
  });
}
activator(user) {
  return () => {
    // mutate the user instance
    user.activate();
    // update the state to trigger render
    this.setState({ user });
  };
}
render (
  var user = this.state.user;
  return (
    <div>
      <span>User {user.isActivated ? 'is' : 'is not'} activated.</span>
      <button onClick={activator(user)}>Activate</button>
    </div>
  );
)
Run Code Online (Sandbox Code Playgroud)

即使这有点hacky并且在状态中存储不可序列化的数据(原型关系,函数)也不是很好.当它处于状态时,我们也会改变对象(eek!).

解决这个问题的一种(可以说是)更优雅的方法是使用一个简单的对象而不用任何实例方法来表示用户.然后编写一组纯操作函数,返回反映更改的新用户对象.

// user factory
function User(args) {
  return {
    id: args.id,
    isActivated: args.isActivated || false
  };
}

function activate(user) {
  // returns a new copy with the isActivated property set to true
  return Object.assign({}, user, { isActivated: true });

  // or with ES2016 object spread
  return { ...user, isActivated: true };
}
Run Code Online (Sandbox Code Playgroud)

我们可以将这些用户对象视为不可变(如果需要,可以冻结它们).然后,您可以修改激活器代码以使其更具功能性.

activator(user) {
  return () => {
    this.setState({ user: activate(user) });
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,当您单击激活按钮时,我们使用新对象更新组件的状态,旧的对象可以自由地进行垃圾回收.

  • 听起来你可能会从Flux架构中受益匪浅.将您的状态从组件移到组件可以订阅的更高级别的存储中.然后,您可以将模型直接映射到道具,这些道具将在更改时重新渲染组件. (3认同)