diff --git a/examples/node/Examples/rn/using-change-listeners-functional-component.js b/examples/node/Examples/rn/using-change-listeners-functional-component.js new file mode 100644 index 0000000000..cd768c3e3a --- /dev/null +++ b/examples/node/Examples/rn/using-change-listeners-functional-component.js @@ -0,0 +1,57 @@ +import React, {useEffect, useState} from 'react'; +import {Text} from 'react-native'; +import Realm from 'realm'; +// :code-block-start: using-change-listeners-functional-component +const TaskList = () => { + const [tasks, setTasks] = useState([]); + // :emphasize-start: + useEffect(() => { + // :emphasize-end: + Realm.open({ + schema: [TaskSchema], // predefined schema + }).then(realm => { + + const tasks = realm.objects('Task'); + // set state to the initial value of your realm objects + setTasks([...tasks]); + + // :emphasize-start: + tasks.addListener(() => { + // update state of tasks to the updated value + setTasks([...tasks]); + }); + // :emphasize-end: + + realm.write(() => { + // the following tasks will trigger the change listener and update the UI + realm.create('Task', { + name: 'Go to the grocery store', + }); + realm.create('Task', { + name: 'Exercise in the gym', + }); + }); + + // cleanup function + // :emphasize-start: + return () => { + const tasks = realm.objects('Task'); + // Remember to remove the listener when you're done! + tasks.removeAllListeners(); + // :emphasize-end: + // Call the close() method when done with a realm instance to avoid memory leaks. + realm.close(); + }; + }); + }, []); + + return ( + <> + {tasks.map(task => ( + {task.name} + ))} + + ); +}; +// :code-block-end: +export default TaskList; \ No newline at end of file diff --git a/examples/node/jest.config.js b/examples/node/jest.config.js index e56d6760ef..155bfd8566 100644 --- a/examples/node/jest.config.js +++ b/examples/node/jest.config.js @@ -6,27 +6,21 @@ module.exports = { projects: [ { displayName: "JavaScript", - moduleFileExtensions: ['js'], - testMatch: [ - "/Examples/**/*.js", - ], - setupFilesAfterEnv: [ - '/testSetup.js', - ], + moduleFileExtensions: ["js"], + testMatch: ["/Examples/**/*.js"], + setupFilesAfterEnv: ["/testSetup.js"], + modulePathIgnorePatterns: ["/Examples/rn"], }, { displayName: "TypeScript", - moduleFileExtensions: ['ts', 'js'], - preset: 'ts-jest/presets/js-with-ts', - setupFilesAfterEnv: [ - '/testSetup.js', - ], - testMatch: [ - "/Examples/**/*.ts", - ], - "transform": { - "^.+\\.ts$": "ts-jest" + moduleFileExtensions: ["ts", "js"], + preset: "ts-jest/presets/js-with-ts", + setupFilesAfterEnv: ["/testSetup.js"], + modulePathIgnorePatterns: ["/Examples/rn"], + testMatch: ["/Examples/**/*.ts"], + transform: { + "^.+\\.ts$": "ts-jest", }, }, - ] + ], }; diff --git a/source/examples/generated/rn/using-change-listeners-functional-component.codeblock.using-change-listeners-functional-component.js.code-block.rst b/source/examples/generated/rn/using-change-listeners-functional-component.codeblock.using-change-listeners-functional-component.js.code-block.rst new file mode 100644 index 0000000000..1d438b1692 --- /dev/null +++ b/source/examples/generated/rn/using-change-listeners-functional-component.codeblock.using-change-listeners-functional-component.js.code-block.rst @@ -0,0 +1,48 @@ +.. code-block:: javascript + :emphasize-lines: 3, 12-15, 28-31 + + const TaskList = () => { + const [tasks, setTasks] = useState([]); + useEffect(() => { + Realm.open({ + schema: [TaskSchema], // predefined schema + }).then(realm => { + + const tasks = realm.objects('Task'); + // set state to the initial value of your realm objects + setTasks([...tasks]); + + tasks.addListener(() => { + // update state of tasks to the updated value + setTasks([...tasks]); + }); + + realm.write(() => { + // the following tasks will trigger the change listener and update the UI + realm.create('Task', { + name: 'Go to the grocery store', + }); + realm.create('Task', { + name: 'Exercise in the gym', + }); + }); + + // cleanup function + return () => { + const tasks = realm.objects('Task'); + // Remember to remove the listener when you're done! + tasks.removeAllListeners(); + // Call the close() method when done with a realm instance to avoid memory leaks. + realm.close(); + }; + }); + }, []); + + return ( + <> + {tasks.map(task => ( + {task.name} + ))} + + ); + }; diff --git a/source/sdk/react-native/examples.txt b/source/sdk/react-native/examples.txt index cb5fd84172..5c272a7e30 100644 --- a/source/sdk/react-native/examples.txt +++ b/source/sdk/react-native/examples.txt @@ -10,6 +10,7 @@ Usage Examples - React Native SDK Open & Close a Local Realm Read & Write Data React to Changes + Use Change Listeners In Components Modify an Object Schema Connect to a MongoDB Realm Backend App Authenticate Users @@ -26,6 +27,7 @@ Realm-Database (Non-Sync) - :doc:`Open & Close a Local Realm ` - :doc:`Read & Write Data ` - :doc:`React to Changes ` +- :doc:`Use Change Listeners In Components ` - :doc:`Modify an Object Schema ` Application Services (Sync) diff --git a/source/sdk/react-native/examples/react-to-changes.txt b/source/sdk/react-native/examples/react-to-changes.txt index 359c3f1cec..1928a494f4 100644 --- a/source/sdk/react-native/examples/react-to-changes.txt +++ b/source/sdk/react-native/examples/react-to-changes.txt @@ -89,4 +89,9 @@ call the instance's ``removeAllListeners()`` function: - :js-sdk:`Realm.Object.removeAllListeners() ` .. literalinclude:: /examples/generated/node/react-to-changes.codeblock.react-to-changes-remove-all-listeners.js - :language: javascript \ No newline at end of file + :language: javascript + +Registering and Removing Listeners From Your React Components +------------------------------------------------------------- +To learn how to register and remove listeners within your application, check out +the documentation on how to :ref:`use change listeners in React components `. diff --git a/source/sdk/react-native/examples/use-change-listeners-in-components.txt b/source/sdk/react-native/examples/use-change-listeners-in-components.txt new file mode 100644 index 0000000000..2f56f5be30 --- /dev/null +++ b/source/sdk/react-native/examples/use-change-listeners-in-components.txt @@ -0,0 +1,63 @@ +.. _react-native-use-listeners-in-components: + +===================================================== +Use Change Listeners In Components - React Native SDK +===================================================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + + +Overview +-------- +You can copy your {+service-short+} objects to your component's :reactjs:`state +`. However, since {+service-short+} objects are +live and automatically update in response to changes, you must update the copies +of them to prevent your UI from drifting out of date with underlying data. You can do this by +registering a :ref:`change listener ` in your +component and updating the state variable when that listener fires. + +.. warning:: + + Failing to update copies of {+service-short+} objects leads to out-of-date data displayed + in your UI as objects are deleted or changed. + +Procedure +~~~~~~~~~ +To keep your UI up-to-date with changes to underlying {+service-short+} objects, +declare a state variable for your {+service-short+} objects using the +:reactjs:`useState() ` hook. + +Within the :reactjs:`useEffect() ` hook, set the state variable to +the initial value of your objects. Then declare a change listener on the +{+service-short+} objects. + +Finally, return an anonymous cleanup function that you can use to remove the +change listener and close the {+service-short+}. React.js will call this cleanup function when +the component unmounts. + +.. example:: + + In the following example, a developer creates an application to manage + tasks. Within a ``TaskList`` component, define a state variable called + ``tasks``. The developer wants to display the initial list of tasks already + saved in the database after the component mounts. To do this, they :ref:`open + a realm ` within a ``useEffect`` function and + then set the ``tasks`` state variable to the initial value of the ``tasks`` + stored in the {+service-short+}. + + The developer registers a change listener to update the state variable when + changes to the ``tasks`` have been made in the {+client-database+}. The + developer then creates some additional tasks. + + Once the component unmounts, the developer wants to unregister the change + listener. To do this, they return a cleanup function and call ``task.removeAllListeners()``. + Finally they :ref:`close the realm `. + + .. include:: /examples/generated/rn/using-change-listeners-functional-component.codeblock.using-change-listeners-functional-component.js.code-block.rst +