Last active
October 11, 2018 20:17
-
-
Save bminer/e9e6f06d80d0de0792cd026d68d9b7ec to your computer and use it in GitHub Desktop.
Revisions
-
bminer revised this gist
Oct 11, 2018 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -22,7 +22,7 @@ is equivalent to: a: { ...comp.state.a, b: { ...comp.state.a.b, c: value } } @@ -47,7 +47,7 @@ are all equivalent to: a: { ...comp.state.a, b: { ...comp.state.a.b, ...value } } @@ -126,9 +126,9 @@ This is roughly equivalent to this monstrosity: a: { ...comp.state.a, b: { ...comp.state.a.b, c: { ...comp.state.a.b.c, d: e.target.value } } -
bminer revised this gist
Oct 9, 2018 . 1 changed file with 0 additions and 11 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -165,14 +165,3 @@ export function updateKeyEvent(component, key, opts) { return e => update(e.target.value); } } -
bminer revised this gist
Oct 9, 2018 . 1 changed file with 16 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -76,17 +76,19 @@ export function updateKey(component, key, opts) { // Deep clone everything along the path to make React happy and // avoid mutating `this.state` directly for (i = 0; i < path.length - 1; i++) { const target = state[path[i]] instanceof Array ? [] : {}; obj[path[i]] = Object.assign(target, state[path[i]]); // Go deeper into `obj` and `state` state = state[path[i]] || {}; // Note: use {} as fail-safe obj = obj[path[i]]; } // Update the value on the deeply cloned Object // There are 2 options: merge Object state or replace state if (merge === undefined) merge = opts.merge; if (merge && typeof value === "object") { // Merge state const target = state[path[i]] instanceof Array ? [] : {}; obj[path[i]] = Object.assign(target, state[path[i]], value); } else { // Replace state obj[path[i]] = value; @@ -163,3 +165,14 @@ export function updateKeyEvent(component, key, opts) { return e => update(e.target.value); } } // Convert camelCase or PascalCase to proper case export function camelToProper(str) { return ( str // insert a space before all caps .replace(/([A-Z])/g, " $1") // uppercase the first character .replace(/^./, str => str.toUpperCase()) ); } -
bminer created this gist
Oct 4, 2018 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,165 @@ /* Returns a function `(value, merge) => {...}` that calls `component.setState(...)` to update the component's state with the new value for `key`. A simple example: const func = updateKey(component, "counter"); func(23); which is equivalent to: component.setState({counter: 23}); `key` can be a nested path into an Object delimited by `.` For example: updateKey(comp, "a.b.c")(value) is equivalent to: comp.setState({ a: { ...comp.state.a, b: { ...comp.state.b, c: value } } }) Note that `a` and `b` are shallowly cloned to prevent direct mutations to `comp.state`. One main purpose of this function is to eliminate a lot of bookkeeping associated with nested object cloning. There is also a `merge` argument that allows the `value` to be merged into the Object located at `key`. For example: updateKey(comp, "a.b")(value, true) // explicitly merge updateKey(comp, "a.b", {merge: true})(value) // merge by default updateKey(comp, "a.b", {merge: false})(value, true) // merge; ignore default are all equivalent to: comp.setState({ a: { ...comp.state.a, b: { ...comp.state.b, ...value } } }) `opts` can be passed to `updateKey` to change some behavior: - `merge` - Sets the default `merge` value for the returned function - `cb` - Callback to be passed to `setState` and called after setting state. */ export function updateKey(component, key, opts) { opts = opts || {}; // Return a function that calls `setState` with custom updater and `cb` return (value, merge) => component.setState((state, props) => { // Split the `key` using "." as delimiter to determine path const path = key.split("."); // Create a `newState` object to be returned const newState = {}; // `state` will point to the current Object in `state` // `obj` will point to the current Object in `newState` let obj = newState; // `i` will keep track of how deep the Object `path` is let i; // Deep clone everything along the path to make React happy and // avoid mutating `this.state` directly for (i = 0; i < path.length - 1; i++) { obj[path[i]] = Object.assign({}, state[path[i]]); // Go deeper into `obj` and `state` state = state[path[i]]; obj = obj[path[i]]; } // Update the value on the deeply cloned Object // There are 2 options: merge Object state or replace state if (merge === undefined) merge = opts.merge; if (merge && typeof value === "object") { // Merge state obj[path[i]] = Object.assign({}, state[path[i]], value); } else { // Replace state obj[path[i]] = value; } return newState; }, opts.cb); } /* Returns a function `(e) => {...}` that calls `component.setState(...)` to update the component's state with the new value for `key` using `e.target.value` as the value. See `updateKey` above for more details. If `e.target` has a `name` property, `{[e.target.name]: e.target.value}` will be merged into `key` instead of replacing the value at `key` with `e.target.value`. Usage in React `render()` function: <input onChange={updateKeyEvent(this, "counter")} /> In the above code, when the <input> is changed, the state's "counter" key will be updated to match the value of the <input>. Another example: <input name="d" onChange={updateKeyEvent(this, "a.b.c")} /> This is roughly equivalent to this monstrosity: <input onChange={(e) => this.setState({ a: { ...comp.state.a, b: { ...comp.state.b, c: { ...comp.state.c, d: e.target.value } } } }) } /> In the above code, when the <input> is changed, `this.setState(...)` will be called such that `this.state.a.b.c` is merged with `{d: value}` where `value` matches the current value of the <input>. `opts` can be passed to change some behavior: - `preventDefault` - By default, `e.preventDefault()` is called. To prevent this call, set `preventDefault` explicitly to `false` ... All other `opts` for `updateKey` */ export function updateKeyEvent(component, key, opts) { opts = opts || {}; const update = updateKey(component, key, opts); if (opts.preventDefault !== false) { // Call `preventDefault` by default unless explicitly set otherwise return e => { e.preventDefault(); const { name, value } = e.target; if (name) { // Special case: merge Object into `key` return update({ [name]: value }, true); } else { return update(value); } }; } else { return e => update(e.target.value); } }