Reputation: 37
I'm using React with mobx to handle application state.
I'm using dump components which alter data through the external store (ajax call, filter or map array etc ...)
Instead in forms, when you have to handle input change through onChange event, currently I'm using observable and action inside the component itself.
Is it a bad practice? Or should I put all the actions and observable data inside an external state?
If instead, this practice is acceptable, how can I address the case in which I have to reset a local observable state (like text input) in reaction to ajax call action executed in an external store? Could i use callback in action store to give up the control to an action inside the component, like in the following example:
import React from 'react';
import { observer, inject } from "mobx-react";
import { observable, action } from "mobx";
@inject("rootStore")
@observer
class ContactForm extends React.Component {
constructor(props) {
super(props);
this.externaStore = this.props.rootStore.contactStore
this.onChangeInput = this.onChangeInput.bind(this)
}
@observable text = ''
@action
onChangeInput(event) {
this.text = event.target.value
}
@action
resetForm() {
this.text = ''
}
render() {
return (
<form>
<div className="form-group">
<label htmlFor="input-text" className="control-label">Text input:
</label>
<input onChange={this.onChangeInput} type="text" value={this.text} id="input-text" name="input-text" className="form-control" />
</div>
<button onClick={() => this.externaStore.submitForm(this.text, this.resetForm)} className="btn btn-danger btn-xs" type="button" title="Aggiungi">
<i className="fa fa-save"></i> Aggiungi
</button>
</form>
)
}
}
class ExternalStore {
constructor(rootStore) {
this.rootStore = rootStore
this.service = rootStore.service
}
@observable textList = []
@action
submitForm(text, cb) {
this.service.doAjax('POST', '/api/text', JSON.stringify(text)).then(data => {
this.textList.push(text)
cb()
})
}
}
Are there another best practice to handle similar cases?
Upvotes: 1
Views: 4223
Reputation: 891
This answer is not correct, even with Mobx. Read the link below for more information. See the documentation under the "@observer component".
https://mobx.js.org/refguide/observer-component.html
The text is copied below as well:
Observable local component state
Just like normal classes, you can introduce observable properties on a component by using the @observable decorator. This means that you can have local state in components that doesn't need to be managed by React's verbose and imperative setState mechanism, but is as powerful. The reactive state will be picked up by render but will not explicitly invoke other React lifecycle methods except componentWillUpdate and componentDidUpdate. If you need other React lifecycle methods, just use the normal React state based APIs.
The example above could also have been written as:
import { observer } from "mobx-react"
import { observable } from "mobx"
@observer
class Timer extends React.Component {
@observable secondsPassed = 0
componentWillMount() {
setInterval(() => {
this.secondsPassed++
}, 1000)
}
render() {
return <span>Seconds passed: {this.secondsPassed} </span>
}
}
ReactDOM.render(<Timer />, document.body)
...Observable local state in hook based components To work with local observable state inside function components, the useLocalStore and useAsObservableSource hooks can be used.
Upvotes: 4
Reputation: 12437
I think the general answer is that MobX (or Redux for that matter) isn't the right place for form state. This is for many reasons, but mainly for performance, complexity and maintainability concerns. MobX/Redux is for global application state, whereas form state is much more local.
The community is moving towards libraries like Formik, that let you fully manage the form state and lifecycle locally within the component. It works well with MobX/Redux too, to optionally initialise the values from global state. Check it out, it's pretty great!
https://github.com/jaredpalmer/formik
Upvotes: 3