Last active
May 29, 2017 10:49
-
-
Save thenikso/ccfebcf5f82b789531fa9b1fb5de73f5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A Mobx friendly utility to ease the late dereference of | |
// objects' observable properties. | |
// Using Ramda here but you can use your own version of these functions | |
import { path, init, last, mapObjIndexed } from 'ramda'; | |
// This is the supporting class, see `late` and `deref` later for actual use | |
class LateDeref { | |
constructor(obj, field) { | |
this.obj = obj; | |
this.fieldPath = field.split('.'); | |
} | |
deref(differentField) { | |
const fieldPath = differentField | |
? differentField.split('.') | |
: this.fieldPath; | |
return path(fieldPath, this.obj); | |
} | |
// If you have a LateDeref object you can late-assign it a value | |
// doing ie: `myLateDeref.set(true)` | |
set(value, differentField) { | |
const fieldPath = differentField | |
? differentField.split('.') | |
: this.fieldPath; | |
const partialDeref = path(init(fieldPath), this.obj); | |
partialDeref[last(fieldPath)] = value; | |
} | |
toString() { | |
return `${this.obj}.${this.fieldPath.join('.')}`; | |
} | |
} | |
// With mobx it is best to dereference an observable as late as possible. | |
// If a component supports a late dereference property (see `deref`), one | |
// can set that property with `late` to dereferene the observable property | |
// as late as possible. | |
// | |
// Supposing that `DisplayName` uses `deref` for its `name` property, instead | |
// of doing: | |
// <DisplayName name={person.name} /> | |
// Prefer: | |
// <DisplayName name={late(person, 'name')} /> | |
// | |
// Note that the field might also be a dot separated path like | |
// `late(person, 'address.street')`. | |
export function late(obj, field) { | |
return new LateDeref(obj, field); | |
} | |
// Identify a `late` property | |
export function isLate(prop) { | |
return prop instanceof LateDeref; | |
} | |
// Use `deref` to dereferene a property that might have a `late` value. | |
// | |
// const DisplayName = observer(({ name }) => <div>{deref(name)}</div>) | |
export function deref(prop) { | |
if (isLate(prop)) { | |
return prop.deref(); | |
} | |
return prop; | |
} | |
// Derefs a props object. The deref will only work through the first level | |
// without going deeper. | |
// | |
// <MyComp {...derefProps(props)} /> | |
export function derefProps(props) { | |
return mapObjIndexed(deref, props); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To clarify, in order to adopt this Mobx/React best practice I found myself creating some weird looking props like
loadingOf
/loadingField
to then do aprop.loadingOf[prop.loadingField]
inside the component. With thislate
/deref
utility I can write a normal looking property (which also act like one for the user) sayloading
and pass it either a bool or alate(this, 'isLoading')
.