Browse Source

React Context API & MobX integration doc (#6116)

What's changed:
- Added a new side bar, `Third party integration` and to that added `React Context API` and `MobX` documentation. 
- Added a limitation of using React Context API with RNN so people are informed of such caveat.
- Informed the readers that if they wish to trigger re-renders across all screens, they need to use the alternatives such as MobX or Redux.
Jin Shin 4 years ago
parent
commit
7b52a3e25d
No account linked to committer's email address
3 changed files with 238 additions and 0 deletions
  1. 117
    0
      website/docs/third-party-mobx.mdx
  2. 117
    0
      website/docs/third-party-react-context.mdx
  3. 4
    0
      website/sidebars.js

+ 117
- 0
website/docs/third-party-mobx.mdx View File

@@ -0,0 +1,117 @@
1
+---
2
+id: third-party-mobx
3
+title: MobX
4
+sidebar_label: MobX
5
+---
6
+
7
+## MobX
8
+MobX is one of the most popular state management libraries used by applications sized from small to large. 
9
+With the introduction of the new React Context API, MobX can now be very easily integrated in React Native Navigation
10
+projects.
11
+
12
+In the example we will be creating a small Counter app.
13
+
14
+:::info Note
15
+With the introduction of the new Context API, there is no need to use `Provider` pattern with MobX and you
16
+can now just use the React Context API.
17
+
18
+Also the example uses `mobx-react-lite` but you can use the normal `mobx-react`.
19
+:::
20
+
21
+## Create a Counter store.
22
+Let's first create a counter store using MobX.
23
+
24
+```tsx
25
+// counter.store.js
26
+import React from 'react'
27
+import { observable, action } from 'mobx'
28
+
29
+class CounterStore {
30
+  @observable count = 0
31
+
32
+  @action.bound
33
+  increment() {
34
+    this.count += 1
35
+  }
36
+
37
+  @action.bound
38
+  decrement() {
39
+    this.count -= 1
40
+  }
41
+}
42
+
43
+// Instantiate the counter store.
44
+const counterStore = new CounterStore()
45
+// Create a React Context with the counter store instance.
46
+export const CounterStoreContext = React.createContext(counterStore)
47
+```
48
+
49
+## Consuming the store
50
+You can consume the Counter store in any React components using `React.useContext`.
51
+
52
+```tsx
53
+// Counter.js
54
+import React from 'react'
55
+import { Button, Text, View } from 'react-native'
56
+import { observer } from 'mobx-react-lite'
57
+import { CounterStoreContext } from './counter.store'
58
+
59
+const CounterScreen = observer(() => {
60
+  const { count, increment, decrement } = React.useContext(CounterStoreContext)
61
+
62
+  return (
63
+    <View>
64
+      <Text>{`Clicked ${count} times!`}</Text>
65
+      <Button title="Increment" onPress={increment} />
66
+      <Button title="Decrement" onPress={decrement} />
67
+    </View>
68
+  )
69
+})
70
+```
71
+
72
+## How to use MobX persistent data
73
+Often the app will require a persistent data solution and with MobX you can use [`mobx-react-persist`](https://github.com/pinqy520/mobx-persist).
74
+It only takes few extra steps to integrate the library.
75
+
76
+```tsx
77
+//counter.store.js
78
+import React from 'react'
79
+import { observable, action } from 'mobx'
80
+import { persist } from 'mobx-persist' // add this.
81
+
82
+class CounterStore {
83
+  @persist @observable count = 0 // count is now persistent.
84
+
85
+  @action.bound
86
+  increment() {
87
+    this.count += 1
88
+  }
89
+
90
+  @action.bound
91
+  decrement() {
92
+    this.count -= 1
93
+  }
94
+}
95
+
96
+export const counterStore = new CounterStore() // You need to export the counterStore instance.
97
+export const CounterStoreContext = React.createContext(counterStore)
98
+
99
+// index.js
100
+import { Navigation } from 'react-native-navigation
101
+import AsyncStorage from '@react-native-community/async-storage'
102
+import { create } from 'mobx-persist'
103
+import { counterStore } from './counter.store // import the counter store instance.
104
+
105
+// Create a store hydration function.
106
+async function hydrateStores() {
107
+  const hydrate = create({ storage: AsyncStorage })
108
+
109
+  await hydrate('CounterStore', counterStore)
110
+}
111
+
112
+Navigation.events().registerAppLaunchedListener(() => {
113
+  hydrateStores().then(() => {
114
+    // ...register screens and start the app.
115
+  })
116
+})
117
+```

+ 117
- 0
website/docs/third-party-react-context.mdx View File

@@ -0,0 +1,117 @@
1
+---
2
+id: third-party-react-context
3
+title: React Context API
4
+sidebar_label: React Context API
5
+---
6
+
7
+## React Context API 
8
+React Context API provides a easy way to pass data through the component tree without having to pass props down 
9
+manually at every level. You can find more about the Context API in [React documentation](https://reactjs.org/docs/context.html).
10
+
11
+You can use the React Context API with React Native Navigation with a limitation. In this example, we are going to create a screen which uses the Counter Context.
12
+
13
+:::important Limitation
14
+As RNN screens are not part of the same component tree, updating the values in the shared context does not trigger a re-render across all screens.
15
+However you can still use the React.Context per RNN screen component tree.
16
+
17
+If you need to trigger a re-render across all screens, there are many popular third party libraries such as 
18
+[MobX](third-party-mobx.mdx) or Redux.
19
+:::
20
+
21
+## Create a Counter context
22
+
23
+```tsx
24
+// CounterContext.js
25
+import React from 'react
26
+
27
+// Declaring the state object globally.
28
+const initialCounterState = {
29
+  count: 0
30
+}
31
+
32
+const counterContextWrapper = (component) => ({
33
+  ...initialCounterState,
34
+  increment: () => {
35
+    initialCounterState.count += 1
36
+    component.setState({ context: contextWrapper(component) })
37
+  },
38
+  decrement: () => {
39
+    initialCounterState.count -= 1
40
+    component.setState({ context: contextWrapper(component) })
41
+  },
42
+})
43
+
44
+export const CounterContext = React.createContext({})
45
+
46
+export class CounterContextProvider extends React.Component {
47
+  state = {
48
+    context: counterContextWrapper(this)
49
+  }
50
+
51
+  render() {
52
+    return (
53
+      <CounterContext.Provider value={this.state.context}>
54
+        {this.props.children}
55
+      </CounterContext.Provider>
56
+    )
57
+  }
58
+}
59
+```
60
+
61
+## Register the screen
62
+When registering the screen that will be using the Counter Context, we need to wrap it
63
+with the Counter Context Provider we created earlier.
64
+
65
+```tsx
66
+// index.js
67
+import { Navigation } from 'react-native-navigation
68
+import { CounterContextProvider } from './CounterContext
69
+import { App } from './App
70
+
71
+Navigation.registerComponent(
72
+  'App', 
73
+  () => props => (
74
+    <CounterContextProvider>
75
+      <App {...props} />
76
+    </CounterContextProvider>
77
+  ),
78
+  () => App
79
+)
80
+```
81
+
82
+## Consuming the context
83
+You can consume the Counter Context any way you want such as `Provider.Consumer` or `React.useContext` like in the 
84
+example below.
85
+
86
+```tsx
87
+// App.js
88
+import React from 'react'
89
+import { Button, Text, View } from 'react-native'
90
+import { CounterContext } from './CounterContext'
91
+
92
+export const App = () => {
93
+  // Using useContext API
94
+  const { count, increment, decrement } = React.useContext(CounterContext)
95
+
96
+  return (
97
+    <View>
98
+      <Text>{`Clicked ${count} times!`}</Text>
99
+      <Button title="Increment" onPress={increment} />
100
+      <Button title="Decrement" onPress={decrement} />
101
+    </View>
102
+  )
103
+
104
+  // Using Context consumer
105
+  return (
106
+    <CounterContext.Consumer>
107
+      {({ count, increment, decrement }) => (
108
+        <View>
109
+          <Text>{`Clicked ${count} times!`}</Text>
110
+          <Button title="Increment" onPress={increment} />
111
+          <Button title="Decrement" onPress={decrement} />
112
+        </View>
113
+      )}
114
+    </CounterContext.Consumer>
115
+  )
116
+}
117
+```

+ 4
- 0
website/sidebars.js View File

@@ -32,6 +32,10 @@ module.exports = {
32 32
       'style-fonts',
33 33
       'style-constants'
34 34
     ],
35
+    'Third party integration': [
36
+      'third-party-react-context',
37
+      'third-party-mobx'
38
+    ],
35 39
     Meta: [
36 40
       'meta-contributing'
37 41
     ]