最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - If using forceUpdate() is discouraged, how should components react to change events in the model? - Stack Overflow

programmeradmin3浏览0评论

I use the following pattern in several ponents throughout my app. I notice that many people discourage using forceUpdate(), and some even call it a hack. So how should this be done without using it?

// 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 {
    ponentDidMount() {
        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);

I use the following pattern in several ponents throughout my app. I notice that many people discourage using forceUpdate(), and some even call it a hack. So how should this be done without using it?

// 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 {
    ponentDidMount() {
        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);
Share Improve this question edited Oct 28, 2017 at 6:54 torvin 7,1114 gold badges38 silver badges53 bronze badges asked Feb 25, 2016 at 3:19 1in7billion1in7billion 3412 gold badges5 silver badges11 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 7

React will automatically render the ponent when either the props or state change.

If you have a model with changing properties then you should either keep it in the ponent's local state.

ponentWillMount() {
  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>
  );
)

Even this is a bit hacky and storing unserializable data (prototype relationships, functions) in state isn't great. We're also mutating the object whilst it's in state (eek!).

An (arguably) more elegant way to solve this problem would be to use a simple object without any instance methods to represent users. Then write a set of pure operation functions that return new user objects reflecting the changes.

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

We can treat these user objects as immutable (freeze them if you want). Then you can modify the activator code to be more functional.

activator(user) {
  return () => {
    this.setState({ user: activate(user) });
  }
}

Now when you click the activate button we update the state of the ponent with a new object and the old one is free to be garbage collected.

Solved using MobX, a reactive paradigm that makes state observable and automatically upates observing ponents.

https://github./mobxjs/mobx

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论