That said, for this example we are going to use the @data-provider/react addon, which provides Data Provider UI bindings for React apps.
React bindings are not included in Data Provider by default. You need to install them explicitly, as well as react-redux, which is a peer dependency of the addon:
This guide assumes that you already know how to create and organize React components. It also assumes that you have installed all needed dependencies to run a React app, have created the required files, as
public/index.html, and have added the needed commands to your
package.json file. If not, you can do it easily using Create React App (if you do so, you can delete all contents inside the
src folder after creating the application, as all needed files inside that folder are the one described in this guide).
The important point to understand here is that we are going to create "Presentational components", which don't have to know anything about Data Provider, and "Container Components" (as they are called in the "Redux - Usage with React" docs), or "Modules", as I like to call them.
The app that we are building in this guide is highly inspired by the one built in the Redux Basic Tutorial, this was made intentionally, as you can compare how the same application is built using Redux, and how using Data Provider. There are two main differences between both applications:
- In our example, we are going to keep the data in server side, instead of keeping it in the client side state.
- We are not going to use Redux directly to handle the state of the current filter. Data Provider usage can be combined without problem with Redux usage. But we want to limit this example to the usage of Data Provider, so the state of the
completedfilter is handled directly by the
TodoList.jsmodule, making it completely reusable. This also has another advantage: We could instantiate many times the
TodoList.jsmodule in the same application at the same time, each one filtering the todos in a different way.
So, for all referent about how to define the "Presentational components", how are they organized and why, we recommend you to read the "Redux - Usage with React" page. There are differences in the way we are going to organize the components, but it can be a good reference. Here we are going to only show the sources, without further explanation, as it is not a Data Provider-specific task.
About what Redux docs call "Container Components", here we are going to call them "Modules" (even when the concept is almost exactly the same), and we are going to explain them in detail, as they are the pieces connected to the Data Provider.
We also have to mention that we are not going to worry about the performance of the example. You'll see here some "React bad patterns" that should be avoided in a real app, as defining callbacks directly in the components props using arrow functions. But again, the purpose of this guide is not to learn about how to use React, so, we made this intentionally in favor of the examples simplicity.
Note the expression
todos && todos.map. We are ensuring that
todoshave value before executing the
mapmethod. This can be easily avoided defining an
initialStatefor the provider or selector. It has been omitted in this guide for simplicity, but it is highly recommended to define the
initialStateto avoid this type of extra checks in the views.
In the "modules" is where we are going to bind the presentational components to the data providers and actions. Note how these pieces could be reused easily in any other application, as they have clearly defined his dependency with the provider they are using.
Here, we simply render the
AddTodo.js component, defining the
onSubmit callback, which in our case will call to the
Here is where we are going to provide the
todos data to the component at charge of rendering them. As input, this module will also receive the value of the current filter, so it can query the provider with the correspondent value.
To connect the provider, we will use the
useLoading methods of the @data-provider/react package. These hooks bind the provider state to the component, so, when any of the chosen properties changes (
loading in this case), the component will be re-rendered. The hooks also will dispatch the
read method of the provider the first time the component is rendered, and will dispatch it again every time its cache is cleaned, so the view will be maintained up to date with the latest data from the provider (and from the server, in this case).
Note the expression
(loading && !todos)that we are using to handle the loading state. Data Provider inform to us when the
todosare being loaded, but we don't want to show the "loading..." indicator every time data is loading. It will be shown only the first time the data is being loaded, while
todoscollection is empty. Rest of times, the current todos state will be shown until the
todosare fetched again, and then replaced. In this way we avoid unwanted flickerings in the UI.
In this component we are going to handle the state of the
completed filter and render both filter and filtered list modules.
We are going to create a separated folder for the "app", which will contain the component rendering the main "layout" and the file at charge of configuring the providers.
We are rendering twice the
TodoListmodule intentionally in order to show how both can live together at the same time, and both will react to the changes in the providers. One will show the uncompleted todos by default, and the other one the completed ones, but you can set the filter of each one without affecting the another.
Data Provide React addon uses react-redux to provide Redux bindings for React, so components need access to the Redux store. To do so, we are going to use the React Redux
Provider, and we are also going to "migrate" the Data Provider store to the store of our app using the Data Provide
We define a namespace for the Data Provider store, and use Redux
combineReducers to migrate it to our app store, in this way, we could define our own application reducers without any conflict. After this, we use the Data Provider
storeManager to set our app store as the Data Provider store, indicating to it the namespace to use. Read the storeManager API for further info.
Here we are also importing the
app/config.jsfile created during the configuration chapter of this guide in order to configure the providers.