1 | Composi
|
2 | =======
|
3 |
|
4 | Contents
|
5 | --------
|
6 | - [Installation](../README.md)
|
7 | - [JSX](./jsx.md)
|
8 | - [Hyperx](./hyperx.md)
|
9 | - [Hyperscript](./hyperscript.md)
|
10 | - [Functional Components](./functional-components.md)
|
11 | - [Mount and Render](./render.md)
|
12 | - [Components](./components.md)
|
13 | - [State](./state.md)
|
14 | - [Lifecycle Methods](./lifecycle.md)
|
15 | - [Events](./events.md)
|
16 | - [Styles](./styles.md)
|
17 | - Unmount
|
18 | - [Third Party Libraries](./third-party.md)
|
19 | - [Deployment](./deployment.md)
|
20 |
|
21 | Unmount
|
22 | -------
|
23 |
|
24 | Components have an `unmount` method. This allows you to destroy a component instance. This does several things.
|
25 |
|
26 | 1. If the component has a `componentWillUnmount` method, it fires this first. Please note that `componentWillUnmount` will be asynchronous. It could take longer to execute than the actual unmounting of the component.
|
27 | 2. It deletes the component from the DOM. It does this based on the base element you used to define your component. This is the same node prepresented by the component's `this.element` value.
|
28 | 3. It nulls out the properties of the component instance for garbage collection.
|
29 |
|
30 | As you may have noticed, there is nothing here to remove any events. Inline events don't need to be removed. They're just properties, afterall. If you've used the `handleEvent` interface, then you'll need to remove the event yourself. You'll need to do this before unmounting the component. Since we use a component's `element` property to bind events, this is easy. Just execute `removeEventListener` on it and pass in the `handleEvent` object.
|
31 |
|
32 | Removing Event from Component Instance
|
33 | --------------------------------------
|
34 |
|
35 | ```javascript
|
36 | import {h, Component} from 'composi'
|
37 |
|
38 | export const list = new Component({
|
39 | container: 'section',
|
40 | render: (fruits) => (
|
41 | <ul>
|
42 | {
|
43 | fruits.map(fruit => <li>{fruit}</li>)
|
44 | }
|
45 | </ul>
|
46 | ),
|
47 | // Pass in component instance so we can bind event listener:
|
48 | componentWasCreated() {
|
49 | list.element.addEventListener('click', eventObj)
|
50 | }
|
51 | })
|
52 |
|
53 | // Define eventHandler object:
|
54 | const eventObj = {
|
55 | handleEvent(e) {
|
56 | eventObj.announceItem(e)
|
57 | },
|
58 | announceItem(e) {
|
59 | alert(e.target.textContent)
|
60 | }
|
61 | }
|
62 |
|
63 | ```
|
64 |
|
65 | To remove the above event before unmounting, we would need to do this:
|
66 |
|
67 | ```javascript
|
68 | // Remove event from component, passing in handleEvent object:
|
69 | list.element.removeEventListener('click', eventObj)
|
70 |
|
71 | // Then we can unmount the component:
|
72 | list.unmount()
|
73 | ```
|
74 |
|
75 |
|
76 | Removing Event from Extended Component
|
77 | --------------------------------------
|
78 |
|
79 | ```javascript
|
80 | import {h, Component} from 'composi'
|
81 |
|
82 | export class List extends Component {
|
83 | constructor(props) {
|
84 | super(props)
|
85 | this.container = 'section'
|
86 | }
|
87 | handleEvent(e) {
|
88 | if (e.target.nodeName === 'LI') {
|
89 | alert(e.target.textContent.trim())
|
90 | } else if (e.target.id === 'add-item') {
|
91 | this.componentShouldUpdate = true
|
92 | const input = this.element.querySelector('input')
|
93 | const value = input.value
|
94 | if (value) {
|
95 | let state = this.state
|
96 | state.unshift({id: String(uuid()), name: value, checked: false})
|
97 | this.state = state
|
98 | input.value = ''
|
99 | }
|
100 | } else if (e.target.type === 'checkbox') {
|
101 | this.componentShouldUpdate = false
|
102 | const id = e.target.closest('li').dataset.id
|
103 | let state = this.state
|
104 | const index = state.findIndex(item => id === item.id)
|
105 | console.log(`The index is: ${index}`)
|
106 | state[index].checked = !state[index].checked
|
107 | this.state = state
|
108 | /**
|
109 | * Remove all events from this component and unmount it!
|
110 | */
|
111 | } else if (e.target.id === 'unmount') {
|
112 | // Unbind event by passing in "this" as reference:
|
113 | this.element.removeEventListener('click', this)
|
114 | // Unmount the component:
|
115 | this.unmount()
|
116 | }
|
117 | }
|
118 | componentWasCreated() {
|
119 | this.element.addEventListener('click', this)
|
120 | }
|
121 | render(data) {
|
122 | return (
|
123 | <div>
|
124 | <p><button id='unmount'>Unmount Component</button></p>
|
125 | <p>
|
126 | <input type="text"/>
|
127 | <button id='add-item'>Add Item</button>
|
128 | </p>
|
129 | <ul class='list'>
|
130 | {
|
131 | data.map(item => <li key={item.id} data-id={item.id}><input type="checkbox" checked={item.checked}/> {item.name}</li>)
|
132 | }
|
133 | </ul>
|
134 | </div>
|
135 | )
|
136 | }
|
137 | }
|
138 | ```
|
139 |
|
140 | In the above example, we really only have one event registered that we are using for all the interactions on this component. This is called event delegation. The `handleEvent` interface makes this easy. Unbinding this event is also easy. Notice in the code slice from the above example how we execute the `removeEventListener` method on the component's `element` property. Then we pass in the 'click' event type. For a reference to the `handleEvent` interface we just pass in `this`. When we set up the event, we did the same.
|
141 | ```javascript
|
142 | // Setup event:
|
143 | this.element.addEventListener('click', this)
|
144 |
|
145 | // Remove event:
|
146 | this.element.removeEventListener('click', this)
|
147 | ```
|
148 | After removing the event, we can unmount it:
|
149 |
|
150 | ```javascript
|
151 | this.unmount()
|
152 | ```
|
153 |
|
154 | Using the `handleEvent` interface when extending the Component class gives us more power and easier to manage events, both adding and removing. Read the documentation for [events](events.md) for more details. |
\ | No newline at end of file |