1

有没有办法用 mobx 做这样的事情?

componentWillUpdate(nextProps) {
  if (this.props.prop !== nextProps.prop) {
    /* side effect, ex. router transition */
  }
}

根据我的经验,this.props.prop总是等于nextProps.prop即使在componentWill-钩子中......

UPD下面是更具体的用例——简单的登录场景:

店铺

class AppStore {
  @observable viewer = new ViewerStore();
}

class ViewerStore {
  @observable id;
  @observable name;
  @observable error;

  fromJSON(json = {}) {
    this.id = json.id;
    this.name = json.name;
  }

  clearError() {
    this.error = null;
  }

  login({ email, password }) {
    fetch('/login', {
      method: 'POST',
      body: JSON.stringify({
        email,
        password
      }),
      credentials: 'same-origin'
    })
    .then(json => {
      this.fromJSON(json);
    })
    .catch(({ error }) => {
      this.error = error;
    })
  }
}

反应部分

class LogInPage extends Component {
  componentWillUpdate(nextProps) {
    if (nextProps.viewer.id && !this.props.viewer.id) {
      this.props.viewer.clearError();
      this.props.onSuccess();
    }
  }

  login = e => {
    e.preventDefault();
    this.props.viewer.login({
      email: e.target.elements['email'].value,
      password: e.target.elements['password'].value,
    });
  }

  render() {
    return (
      <div>
        <h1>Log In</h1>
        <form onSuccess={this.login}>
          <input type="text" name="email" />
          <input type="password" name="password" />
          <input type="submit" />
        </form>
        { this.props.viewer.error && (
          <div>
            <b>Error</b>: {this.props.viewer.error}
          </div>
        )}
      </div>
    );
  }
}

const store = new AppStore();
ReactDOM.render(<LogInPage 
  viewer={store.viewer}
  onSuccess={() => alert("Hello!")}  
 />
, container);

所以基本上,我只想在观众id切换到某事时undefined能够做某事

4

3 回答 3

2

感谢您的更新,这澄清了很多问题。@observer这在一定程度上取决于您想要做什么,但是如果您想更改组件的呈现方式,只需从mobx-react包中装饰您的组件就足够了。然后它将在商店更改时自动重新渲染。

如果你想做任何额外的动作,你可以在你的componentWillMount. 喜欢

componentWillMount() {
    this.autorunDisposer = mobx.autorun(() => {
        if (nextProps.viewer.id && !this.props.viewer.id) {
            this.props.viewer.clearError();
            this.props.onSuccess();
        }
    })
}

但是我不经常看到这种模式,因为在你的商店中拥有这种逻辑通常会更干净。就我个人而言,我希望登录表单组件大致如下所示:

@observer class RequiresLogin extends Component {
    render() {
        if (this.props.viewerStore.id !== undefined) {
            return this.props.children
        } else {
            return <LoginPage viewer={this.props.viewerStore}/>
        }
    }
}

@observer class MyTestPage extends Component {
    render() {
        return <RequiresLogin viewer={this.props.viewerStore}>
            Secret Area!
        </RequiresLogin>
    }
}

@observer class LogInPage extends Component {
  login = e => {
    e.preventDefault();
    this.props.viewer.login({
      // tip: use React refs or the onChange handler to update local state:
      email: e.target.elements['email'].value,
      password: e.target.elements['password'].value,
    });
  }

  render() {
    if (this.props.viewer.id)
        return null; // no need to show login form
    return (
      <div>
        <h1>Log In</h1>
        <form onSuccess={this.login}>
          <input type="text" name="email" />
          <input type="password" name="password" />
          <input type="submit" />
        </form>
        { this.props.viewer.error && (
          <div>
            <b>Error</b>: {this.props.viewer.error}
          </div>
        )}
      </div>
    );
  }
}
于 2016-05-12T17:59:44.763 回答
1

在 99.9% 的情况下,发生这种情况是因为您的代码道具中的其他地方直接发生了变异。这在反应中是不允许的。

典型场景包括:

var myObject = this.props.someObject;  // myObject is a POINTER to props, not copy
myObject.attribute = newAttribute;     // Now props are directly mutated

var myArray = this.props.someArray;
myArray.splice(a,b);                   // splice directly mutates array

要解决此问题,请在更新道具之前制作道具对象的正确副本。

于 2016-05-12T14:10:56.953 回答
1

好吧,实际上问题发生了,因为我将 store 作为单个 prop 传递(以便mobx调用它的方法this.props.store.update(),如mobxnextProps

当我需要这种检查时,我最终将 store 解构为组件的 props。

于 2016-05-12T16:23:29.713 回答