From d95249b0f77bd75b89ee278e1ca82045a5963f9e Mon Sep 17 00:00:00 2001 From: Spen Taylor Date: Wed, 2 Nov 2016 19:45:08 +1100 Subject: [PATCH] feat(docs): Update ImmutableJS docs for grammar and add more reference links to ImmutableJS docs (#1126) --- docs/js/immutablejs.md | 61 ++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/docs/js/immutablejs.md b/docs/js/immutablejs.md index 2dfebe27fa..b4fe5a2675 100644 --- a/docs/js/immutablejs.md +++ b/docs/js/immutablejs.md @@ -11,22 +11,26 @@ for a good explanation of the more intricate benefits it has. In our reducers, we make the initial state an immutable data structure with the `fromJS` function. We pass it an object or an array, and it takes care of -converting it to a compatible one. (Note: the conversion is performed deeply so -that even arbitrarily nested arrays/objects are immutable stuctures too!) +converting it to a immutable data structure. (Note: the conversion is performed deeply so +that even arbitrarily nested arrays/objects are immutable structures too!) ```JS import { fromJS } from 'immutable'; const initialState = fromJS({ - myData: 'Hello World!', + myData: { + message: 'Hello World!' + }, }); ``` -To react to an incoming actions our reducers can use the `.set` and the `.setIn` -functions. + + +When a reducer is subscribed to an action and needs to return the new state they can do so by using setter methods such as [`.set`](https://facebook.github.io/immutable-js/docs/#/Map/set) and [`.update`](https://facebook.github.io/immutable-js/docs/#/Map/update) and [`.merge`](https://facebook.github.io/immutable-js/docs/#/Map/merge). +If the changing state data is nested, we can utilize the 'deep' versions of these setters: [`.setIn`](https://facebook.github.io/immutable-js/docs/#/Map/setIn) and [`.updateIn`](https://facebook.github.io/immutable-js/docs/#/Map/updateIn), [`.mergeIn`](https://facebook.github.io/immutable-js/docs/#/Map/mergeIn). ```JS -import { SOME_ACTION } from './actions'; +import { SOME_ACTION, SOME_OTHER_ACTION } from './actions'; // […] @@ -34,6 +38,8 @@ function myReducer(state = initialState, action) { switch (action.type) { case SOME_ACTION: return state.set('myData', action.payload); + case SOME_OTHER_ACTION: + return state.setIn(['myData', 'message'], action.payload); default: return state; } @@ -41,36 +47,57 @@ function myReducer(state = initialState, action) { ``` We use [`reselect`](./reselect.md) to efficiently cache our computed application -state. Since that state is now immutable, we need to use the `.get` and `.getIn` +state. Since that state is now immutable, we need to use the [`.get`](https://facebook.github.io/immutable-js/docs/#/Iterable/get) and [`.getIn`](https://facebook.github.io/immutable-js/docs/#/Iterable/getIn) functions to select the part we want. ```JS const myDataSelector = (state) => state.get('myData'); +const messageSelector = (state) => state.getIn(['myData', 'message']); export default myDataSelector; ``` To learn more, check out [`reselect.md`](reselect.md)! -## Advanced Usage - -ImmutableJS provide many immutable structures like `Map`, `Set` and `List`. But the downside to using ImmutableJS data structures is that they are not normal JavaScript data structures. +## Immutable Records -That means you must use getters to access properties : for instance you'll do `map.get("property")` instead of `map.property`, and `array.get(0)` instead of `array[0]`. It's not natural and your code becoming bigger, you finish by not knowing anymore if you are working with a JavaScript object or an Immutable one. While it's possible to be clear where you are using immutable objects, you still pass them through the system into places where it's not clear. This makes reasoning about functions harder. +ImmutableJS provides a number of immutable structures such as [`Map`](https://facebook.github.io/immutable-js/docs/#/Map), [`Set`](https://facebook.github.io/immutable-js/docs/#/Set) and [`List`](https://facebook.github.io/immutable-js/docs/#/List). +One drawback to these structures is that properties must be accessed via the getter methods (`.get` or `.getIn`) and cannot be accessed with dot notation as they would in a plain javascript object. +For instance you'll write `map.get('property')` instead of `object.property`, and `list.get(0)` instead of `array[0]`. +This can make your code a little harder to follow and requires you to be extra cautious when passing arguments or props to functions or components that try to access values with regular dot notation. +ImmutableJS's [`Record`](https://facebook.github.io/immutable-js/docs/#/Record) structure offers a solution to this issue. -The `Record` structure tries to get rid of this drawback. `Record` is like a `Map` whose shape is fixed : you can't later add a new property after the record is created. The benefit of `Record` is that you can now, along with others .get, .set and .merge methods, use the dot notation to access properties, which is a good point to write simpler code. +A `Record` is similar to a `Map` but has a fixed shape, meaning it's property keys are predefined and you can't later add a new property after the record is created. Attempting to set new properties will cause an error. +One benefit of `Record` is that you can now, along with other immutable read methods (.get, .set, .merge and so on), use the dot notation to access properties. -The creation of a record is less simple. You got to first create the `Record` shape. With the example above, to create your initial state, you'll write : +The creation of a record is less simple than simply calling `.toJS()`. +First, you have to define the `Record` shape. With the example above, to create your initial state, you'll write: ```JS -//the shape +// Defining the shape const StateRecord = Record({ - myData: 'Hello World!', + myData: { + message: 'Hello World!' + } }); const initialState = new StateRecord({}); // initialState is now a new StateRecord instance - // initialized with myData set by default as 'Hello World!' + // initialized with myData.message set by default as 'Hello World!' ``` -Now, if you want to access `myData`, you can just write `state.myData` in your reducer code. +Now, if you want to access `myData`, you can just write `state.myData` in your reducer code and to access the `message` property you can write `state.myData.message` as you would in a plain javascript object. + +### Gotchas of Using Records + +Although dot notation can now be used to read properties the same does not apply to setting properties. Any attempts to set a property on a `Record` using dot notation will result in errors. +Instead setter methods ( `.set`, `.update`, `.merge`) should be used. + +Certain properties can not be set on a record as they would conflict with the API. Consider the below example: +```JS +const ProductRecord = Record({ + type: 'tshirt', + size: 'small' +}); +``` +Because record.size is used to return the records count (similar to array.length), the above definition would throw an error. \ No newline at end of file