UNPKG

6.1 kBMarkdownView Raw
1# Component-DataStore
2
3This contains three classes: DataStore, DataStoreComponent and Observer. These enable creating Composi class components using a `dataStore` for state management. When the `dataStore` is modified, it automatically updates the component.
4
5
6## Installation
7
8To install, run the following:
9
10```
11npm i --save composi-datastore
12```
13
14Then import DataStore and DataStoreComponent into your app:
15
16```javascript
17import { h, Component } from 'composi'
18import { DataStore, DataStoreComponent } from 'composi-datastore'
19```
20
21## Create a `dataStore`
22
23With these imported, you can now create a `dataStore`. You do this by passing an object with a state property which defines the data you want the `dataStore` to manage.
24
25```javascript
26const dataStore = new DataStore({
27 state: {
28 message: 'This is a simple dataStore',
29 items: [
30 {
31 id: 101,
32 value: 'Apples'
33 },
34 {
35 id: 102,
36 value: 'Oranges'
37 }
38 ]
39 }
40})
41```
42
43## Define an `actions` Object
44
45Next we can create an `actions` object that our component will use. Actions will be methods that operate on the `dataStore`. Notice that we are passing the `dataStore` as the first argument of each method. This is so we can use its `setState` method to update the data and trigger a re-render of the component. The second arguemnt is any data we need for whatever data manipulation we need to do:
46
47```javascript
48const actions = {
49 addItem(dataStore, data) {
50 dataStore.setState(prevState => {
51 prevState.items.push({
52 id: data.id,
53 value: data.value
54 })
55 return prevState
56 })
57 },
58 deleteItem(dataStore, id) {
59 dataStore.setState(prevState => {
60 prevState.items = prevState.items.filter(item => item.id != id)
61 return prevState
62 })
63 }
64}
65```
66
67## Extend DataStoreComopnent Class
68
69And finally we need to create a component using the `DataStoreComponent` class. We do this just like we would with `Component`, by extending it. `DataStoreComponent` is an extension of `Component`, so the same lifecyle hooks and `render` function are available. Notice how we use the `dataStore` in the two methods that update state.
70
71```javascript
72class List extends DataStoreComponent {
73 key = 103
74 render(data) {
75 return (
76 <div class='list-container'>
77 <h2>{data.message}</h2>
78 <p>
79 <input type="text"/>
80 <button className="add-item" onclick={() => this.addItem()}>Add</button>
81 </p>
82 <ul>
83 {
84 data.items.map(item => (
85 <li key={item.id}>
86 <span>{item.value}</span>
87 <button className="delete-item" onclick={() => this.deleteItem(item.id)}>X</button>
88 </li>)
89 )
90 }
91 </ul>
92 </div>
93 )
94 }
95 componentDidMount() {
96 this.input = this.element.querySelector('input')
97 this.input.focus()
98 }
99 addItem() {
100 const value = this.input.value
101 if (value) {
102 // Use the actions method to udpate the dataStore:
103 actions.addItem(this.dataStore, {id: this.key++, value})
104 this.input.value = ''
105 this.input.focus()
106 } else {
107 alert('Please provide a value before submitting.')
108 }
109 }
110 deleteItem(id) {
111 // Use the actions method to udpate the dataStore:
112 actions.deleteItem(this.dataStore, id)
113 }
114}
115```
116
117## Instantiate the Component
118
119Now that we have a custom component derived from `DataStoreComponent`, we can create an instance. Like a normal Component instance, we pass it an object literal with several properties. The first is the container to render the component in. The second is the `dataStore` to use.
120
121After create the instance with the `new` keyword, we need to invoke the `update` method on it, passing in the `dataStore` state. This is because, unlike stateful components, components derived from `DataStoreComponent` don't have state. Their state is being handle by the `dataStore`. So, to trigger the first render, you need to pass the `dataStore` to the component through the `update` method. After that, any updates to the `dataStore` will trigger a re-render of the component.
122
123```javascript
124const list = new List({
125 container: 'section',
126 dataStore
127})
128
129list.update(dataStore.state)
130```
131
132### Default DataStore Event
133`DataStore` uses `dataStoreStateChanged` as the default event in conjunction with `DataStoreComponent`. So DO NOT USE this for your own watchers. It will render your `DataStoreComponent` incapable of update when the dataStore changes.
134
135## Observer
136
137This is a simple observer class with just two methods: `watch` and `dispatch`. Can't get any simpler than that. To use it, import it into your project:
138
139```javascript
140import { Observer } from 'composi-datastore'
141```
142
143After that you can create a new instance of `Observer`:
144
145```javascript
146const observer = new Observer()
147```
148
149After creating a new observer, you can set up watchers and when appropriate dispatch to them. You tell the observer to watch events and give them a callback to execute when the event happens. Dispatch announces the event and optionally passes some data along with it. Note, you don't need to send data. An watcher can just be waiting for an event to happen.
150
151```javascript
152import { Observer } from 'composi-datastore'
153
154const observer = new Observer()
155
156function callback(data) {
157 console.log(`This is the event: ${data}`)
158}
159
160observer.watch('test', callback)
161
162// Sometime later:
163observer.dispatch('test', 'Sending a message to the observer.')
164```
165
166### Events
167
168The observer stores its events on its `events` property. If we took the `observer` from the above example, we could examine its events like this:
169
170```javascript
171console.log(oberser.events)
172/**
173 returns: {test: [
174 function (t){console.log("This is the event: "+t)}
175]}
176*/
177```
178
179### TODO
180
181Implement Jest tests for `DataStoreComponent`. Since this has a dependency on a Node module (composi), I haven't been able to create a test that works. Seems Jest has problems dealing with ES6 `import/export` with Babel. Have tried all kinds of configs, but Jest fails to import Composi module.
\No newline at end of file