-
Hello everyone, I'm having trouble understanding the anti-pattern of triggering an The code below shows what I think would be a good solution to my use case. In the example, I want to clean the field But apparently using a reaction to change another value in my model is a MobX anti-pattern. Finally, my question is: Modelclass Form {
public petType = "";
public breed = "";
public availablePetTypes: string[] = [];
public availableBreeds: Breed[] = [];
constructor() {
mobx.makeObservable(this, {
petType: mobx.observable,
breed: mobx.observable,
availableBreeds: mobx.observable,
availablePetTypes: mobx.observable,
setPetType: mobx.action,
setBreed: mobx.action,
addAvailablePetType: mobx.action,
addAvailableBreed: mobx.action,
validBreeds: mobx.computed
});
}
get validBreeds(): Breed[] {
return this.availableBreeds.filter(
({ petType }) => petType === this.petType
);
}
// setters
public setPetType(petType: string): void {
this.petType = petType;
}
public setBreed(breed: string): void {
this.breed = breed;
}
public addAvailablePetType(petType: string[]): void {
this.availablePetTypes = petType;
}
public addAvailableBreed(breeds: Breed[]): void {
this.availableBreeds = breeds;
}
}
interface Breed {
petType: string;
breed: string;
} Data setup// setup:
const form = new Form();
form.addAvailablePetType(["cat", "dog"]);
form.addAvailableBreed([
{
breed: "Brazilian Shorthair",
petType: "cat"
},
{
breed: "Siamese",
petType: "cat"
},
{
breed: "Corgi",
petType: "dog"
},
{
breed: "Bulldog",
petType: "dog"
}
]); Input jquery binding// binding in the screen
$("#pet-type").keyup(function(this: JQuery, event) {
const value = $(this).val();
form.setPetType(value);
}); And this is how I thought I would write my business rules: mobx.reaction(
() => form.validBreeds,
(validBreeds: Breed[]) => {
if (!currentBreedIsStillValid(validBreeds)) {
form.setBreed("");
}
}
);
function currentBreedIsStillValid(validBreeds: Breed[]) {
return validBreeds.some(({ breed }) => breed === form.breed);
} Solution with the validation in the setter function setPetType(petType: string): void {
this.petType = petType;
if (!currentBreedIsStillValid(this.breed)) {
this.breed = "";
}
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
If the business rule is that the field must be validated every time it's being modified, then setting a value and validating a value is coupled by design - there must be a place that couples these two actions and makes sure that you cannot invoke one without the other.
Avoid the need for doing so by designing things differently, use composition. |
Beta Was this translation helpful? Give feedback.
If the business rule is that the field must be validated every time it's being modified, then setting a value and validating a value is coupled by design - there must be a place that couples these two actions and makes sure that you cannot invoke one without the other.
Reaction is basically globally shared event bus, it doesn't remove coupling, it just allows you to create the coupling ad-hoc - you can connect (and disconnect) anything to anything anytime anywhere. How do you want to reason about something like that?
Consider you want to know how the state changes when
form.setPetType(value);
is called. Unless someone gives you a list of all reactions you're unable to tell. But even then …