UNPKG

3.17 kBJavaScriptView Raw
1import { EMPTY_OBJECT, merge, isObject, uuid } from '../lib/utils'
2import { Observer } from './observer'
3
4/**
5 * A uuid to use as the property of the dataStore's state. This creates a pseudo-private
6 */
7const dataStore = uuid()
8
9/**
10 * A class to create a dataStore. This is used in conjunction with DataStoreComponent to create stateless components with external state management through a dataStore.
11 */
12export class DataStore {
13 constructor(props) {
14 this[dataStore] = undefined
15 this.observer = new Observer()
16 this.state = props.state
17 }
18
19 /**
20 * @method This is a getter to access the component's state using the pseudo-private key dataStore.
21 * @return {boolean | number | string | Object | any[]} The component's state
22 */
23 get state() {
24 return this[dataStore]
25 }
26
27 /**
28 * @method This is a setter to define the component's state. It uses the dataStore object as a pseudo-private key. It uses requestAnimationFrame to throttle component updates to avoid layout thrashing.
29 * @param {string | number | boolean | Object | any[]} data Data to set as component state.
30 * @return {void} undefined
31 */
32 set state(data) {
33 this[dataStore] = data
34 this.dispatch('dataStoreStateChanged', this.state)
35 }
36
37 /**
38 * @method This is a method to dispatch an event with data to a DataStoreComponent that is using a dataStore.
39 * @param {string} event The name of the event that the component is watching.
40 * @param {any} data Any data you want to send to the component.
41 */
42 dispatch(event, data) {
43 this.observer.dispatch(event, data)
44 }
45
46 /**
47 * @method This method sets up an observer to listener for the designated event and do something with any data passed along.
48 * @param {string} event The event to watch.
49 * @param {any} data Any data that the event callback will need to handle.
50 */
51 watch(event, data) {
52 this.observer.watch(event, data)
53 }
54
55 /**
56 * @method Method to set a dataStore's state. This accepts simple types or Objects. If updating an array, you can pass in the data and the position (number) in the array to update. Optionally you can pass a callback, which receives the state as its argument. You need to return the state changes in order for the component to be updated.
57 * @example Set state on a dataStore:
58 *
59 * ```
60 * this.setState(true)
61 * this.setState(0)
62 * this.setState({name: 'Joe'})
63 * this.setState([1,2,3])
64 * this.setState(prevState => prevState + 1)
65 ```
66 * @param {string | number | boolean | Object | any[] | Function} data The data to set. If a callback is passed as the argument to execute, it gets passed the previous state as its argument. You need to make sure the callback returns the final state or the component will not update.
67 * @return {void} undefined
68 */
69 setState(data) {
70 if (typeof data === 'function') {
71 let copyOfState
72 copyOfState = merge(EMPTY_OBJECT, this.state)
73 const newState = data.call(this, copyOfState)
74 if (newState) this.state = newState
75 } else if (isObject(this.state) && isObject(data)) {
76 const newState = merge(this.state, data)
77 this.state = newState
78 }
79 }
80}