# Redux

[View on Github](https://github.com/CartoDB/carto-react-template)

{% hint style="warning" %}
**Note:** We are reducing our investment in CARTO for React and currently we discourage users from starting new projects with it.

CARTO for React is an opinionated framework with pre-built components and templates. This greatly speeds up the process to create React-based applications, but customization options are limited.

If you need further customization in React, or you want to build geospatial applications using **Vue, Angular, or any other Javascript-based framework**, we recommend going directly to the main CARTO for Developers documentation, including [CARTO + deck.gl](https://github.com/CartoDB/gitbook-documentation/blob/master/carto-for-developers/key-concepts/carto-for-deck.gl), which allows for maximum flexibility and scalability.
{% endhint %}

| Package            | Version                                                                                                                           | Downloads                                                                                                                            |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| @carto/react-redux | [![version](https://img.shields.io/npm/v/@carto/react-redux.svg?style=flat-square)](https://npmjs.org/package/@carto/react-redux) | [![downloads](https://img.shields.io/npm/dt/@carto/react-redux.svg?style=flat-square)](https://npmjs.org/package/@carto/react-redux) |

Functions to manage application state using React-Redux and the Redux Toolkit. This package includes 2 slices to manage the main redux blocks of a CARTO for React application. A [slice](#oauth-slice) is a way to manage a “portion” or *slice* of the redux store with a module:

* `cartoSlice`: to deal with basemap, viewState, sources, layers, and filters on sources.
* `oauthSlice`: to use an OAuth app.

**Tip:** The CARTO for React template already makes extensive use of these slices for redux out of the box, to provide several features in an easy way.

## CARTO Slice <a href="#carto-slice" id="carto-slice"></a>

### **createCartoSlice**

A function that accepts an `initialState`, setups the state, and creates the reducers that support CARTO for React architecture. In the CARTO 3 templates this slice includes also the OAuth settings; in the CARTO 2 templates there is a separate [slice](https://docs.carto.com/react/library-reference/redux/#oauth-slice) for OAuth settings.

* **Input**:

| Param        | Type     | Description       |
| ------------ | -------- | ----------------- |
| initialState | `Object` | the initial state |

An initial state object might look like:

```jsx
import { POSITRON } from "@carto/react-basemaps";

export const initialState = {
  viewState: {
    latitude: 31.802892,
    longitude: -103.007813,
    zoom: 2,
    pitch: 0,
    bearing: 0,
    dragRotate: false,
  },
  basemap: POSITRON,
  credentials: {
    username: "public",
    apiKey: "default_public",
    serverUrlTemplate: "https://{user}.carto.com",
  },
  googleApiKey: "",
};
```

### **addSource**

Action to add a **source** to the store.

* **Input**:

| Param                        | Type                               | Description                                                                                                                                                                                                             |
| ---------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| props                        | `Object`                           | { id, data, type, credentials, connection }                                                                                                                                                                             |
| props.id                     | `string`                           | Unique id for the source                                                                                                                                                                                                |
| props.data                   | `string`                           | Table name, tileset name or SQL query                                                                                                                                                                                   |
| props.type                   | `string`                           | Source type. Check available types [here](https://docs.carto.com/deck-gl/reference#type-string)                                                                                                                         |
| props.credentials            | `string`                           | Credentials for accessing the source                                                                                                                                                                                    |
| props.connection             | `string`                           | Connection name. Used only for CARTO 3.                                                                                                                                                                                 |
| props.filtersLogicalOperator | `FiltersLogicalOperators`          | Logical operation to use for combining filters. Can take the values `FiltersLogicalOperators.AND` and `FiltersLogicalOperators.OR`. Default value is `AND`. *Note: this property is only available beginning with v1.3* |
| \[props.queryParameters]     | `QueryParameters (@deck.gl/carto)` | Optional. SQL query parameters                                                                                                                                                                                          |

* **Example**:

```jsx
import { addSource } from "@carto/react-redux";
import { MAP_TYPES } from '@deck.gl/carto';

const source = {
  id: "sourceOne",
  type: MAP_TYPES.QUERY,
  connection: 'bqconn',
  data: "SELECT * FROM my_table",
  filtersLogicalOperator: FiltersLogicalOperators.OR
};

const action = addSource(source);
// dispatch(action);
```

### **removeSource**

Action to remove a source from the store

* **Input**:

| Param    | Type     | Description                |
| -------- | -------- | -------------------------- |
| sourceId | `string` | id of the source to remove |

* **Example**:

```jsx
import { removeSource } from "@carto/react-redux";

const action = removeSource("sourceOne");
// dispatch(action);
```

### **addLayer**

Action to add a Layer to the store. By default, the layer `visible` attribute is set to `true` unless the `layerAttributes` property overrides the `visible` property.

Important! This doesn’t imply adding a whole deck.gl layer to the redux store, just a “pointer” to it, by using an `id` shared with a Layer file + linking it to a `source`. See code generated by hygen assistants in the create-react-app template projects.

* **Input**:

| Param                    | Type     | Description                                       |
| ------------------------ | -------- | ------------------------------------------------- |
| props                    | `Object` | { id, source, layerAttributes }                   |
| props.id                 | `string` | unique id for the layer                           |
| props.source             | `string` | id of the source of the layer                     |
| \[props.layerAttributes] | `Object` | (optional) custom attributes to pass to the layer |

* **Example**:

```jsx
const action = addLayer({
  id: "layerOne",
  source: "sourceOne",
  layerAttributes: {
    extraAttribute: 1,
  },
});
// dispatch(action);
// extraAttribute will be available inside the Layer, for custom operations inside it (eg. styling)
```

### **updateLayer**

Action to update a Layer in the store

* **Input**:

| Param                 | Type     | Description                                        |
| --------------------- | -------- | -------------------------------------------------- |
| props                 | `Object` | { id, layerAttributes }                            |
| props.id              | `string` | unique id for the CARTO layer already in the store |
| props.layerAttributes | `Object` | custom attributes to update in the layer           |

* **Example**:

```jsx
const action = updateLayer({
  id: "layerOne",
  layerAttributes: {
    extraAttribute: 100,
  },
});
// dispatch(action);
// extraAttribute will be updated to the new value
```

### **removeLayer**

Action to remove a layer from the store

* **Input**:

| Param | Type     | Description               |
| ----- | -------- | ------------------------- |
| id    | `string` | id of the layer to remove |

* **Example**:

```jsx
const action = removeLayer("layerOne");
// dispatch(action);
```

### **setCredentials**

Action to set the default credentials parameters to use for requests to the CARTO platform.

* **Input**:

| Param       | Type     | Description                                                                                                                                         |
| ----------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| credentials | `Object` | CARTO platform credentials. Check the parameters [here](https://docs.carto.com/development-tools/carto-for-deck.gl/reference#setdefaultcredentials) |

* **Example**:

```jsx
import { API_VERSIONS } from "@deck.gl/carto";
import { setCredentials } from "@carto/react-redux";

      
const action = setCredentials({ 
  apiBaseUrl: 'https://gcp-us-east1.api.carto.com',
  apiVersion: API_VERSIONS.V3,
  accessToken: 'eyJhb...'
});
// dispatch(action);
```

### **setBasemap**

Action to set a basemap. To see available maps, check the reference for `@carto/react-basemaps`. If you use a Google Maps basemap, you would need to manage its api\_key properly.

* **Input**:

| Param   | Type     | Description            |
| ------- | -------- | ---------------------- |
| basemap | `String` | the new basemap to add |

* **Example**:

```jsx
import { DARK_MATTER } from "@carto/react-basemaps";
import { setBasemap } from "@carto/react-redux";

const action = setBasemap(DARK_MATTER);
// dispatch(action);
```

### **addFilter**

Action to add a filter on a given `source` by a `column`. This is done internally (and in a transparent way) by widgets.

* **Input**:

| Param           | Type         | Description                                                                 |
| --------------- | ------------ | --------------------------------------------------------------------------- |
| props           | `Object`     | { id, column, type, values, \[owner], \[params]}                            |
| props.id        | `string`     | Identifier of the source to apply the filter on                             |
| props.column    | `string`     | Column from the source to use by the filter                                 |
| props.type      | `FilterType` | Type of filter                                                              |
| props.values    | `array`      | Values for the filter (eg: \[‘a’, ‘b’] for ‘in’ or \[10, 20] for ‘between’) |
| \[props.owner]  | `string`     | (optional) Identifier of the widget triggering the filter (to be excluded)  |
| \[props.params] | `object`     | (optional) Additional filter parameters (depending on filter type)          |

* **Example**:

  This would apply a filter equivalent to a ‘WHERE country IN (‘Spain’)’ to the source. It is important to notice that a source can have multiple filters at the same type.

```jsx
import { addFilter } from "@carto/react-redux";

const action = addFilter({
  id: "sourceOne", // a valid sourceId
  column: "country",
  type: "in",
  values: ["Spain"],
});

// dispatch(action)
```

### **removeFilter**

Action to remove a column filter from a source.

* **Input**:

| Param        | Type     | Description                                      |
| ------------ | -------- | ------------------------------------------------ |
| props        | `Object` | { id, column }                                   |
| props.id     | `string` | sourceId of the source to remove the filter from |
| props.column | `string` | column of the filter to remove                   |

* **Example**:

  This would remove a filter (the previous example on addFilter)

```jsx
import { removeFilter } from "@carto/react-redux";

const action = removeFilter({
  id: "sourceOne",
  column: "country",
});

// dispatch(action)
```

### **clearFilters**

Action to remove all filters from a source.

* **Input**:

| Type | Description                                       |
| ---- | ------------------------------------------------- |
| `id` | sourceId of the source to remove all filters from |

* **Example**:

  This would remove all filters from a source with id ‘sourceOne’

```jsx
import { clearFilters } from "@carto/react-redux";

const action = clearFilters("sourceOne");

// dispatch(action)
```

### **selectSourceById**

Redux selector to get a source by ID

* **Input**:

| Param    | Type     | Description                            |
| -------- | -------- | -------------------------------------- |
| state    | `Object` | root redux state                       |
| sourceId | `string` | id of the source to recover from redux |

* **Example**:

```jsx
import { useSelector } from "react-redux";
import { selectSourceById } from "@carto/react-redux";

const source = useSelector((state) => selectSourceById(state, "sourceOne") || {});

// source is now available, for further operations
```

### **setViewState**

Action to set the current ViewState of the map.

* **Input**:

| Param     | Type     | Description                      |
| --------- | -------- | -------------------------------- |
| viewState | `Object` | ViewState, as defined by deck.gl |

* **Example** Example to increase the zoom level

```jsx
import { useSelector } from "react-redux";
import { setViewState } from "@carto/react-redux";

const zoomLevel = useSelector((state) => state.carto.viewState.zoom);
const action = setViewState({ zoom: zoomLevel + 1 });

// dispatch(action)
```

### **setWidgetLoadingState**

Action to set the loading state to a specific widget. It can be useful when creating custom widgets.

* **Input**:

| Param           | Type      | Description            |
| --------------- | --------- | ---------------------- |
| props           | `Object`  | { widgetId, isLoading} |
| props.widgetId  | `string`  | id of the widget       |
| props.isLoading | `boolean` | loading state          |

### **removeWidgetLoadingState**

Action to remove a specific widget loading state

* **Input**:

| Param    | Type     | Description      |
| -------- | -------- | ---------------- |
| widgetId | `string` | id of the widget |

### **setAllWidgetsLoadingStates**

Action to set the all the widgets loading state at once

* **Input**:

| Param      | Type      | Description   |
| ---------- | --------- | ------------- |
| areLoading | `boolean` | loading state |

## OAuth Slice <a href="#oauth-slice" id="oauth-slice"></a>

### **createOauthCartoSlice**

A function that accepts an initialState, setup the state, and creates reducers to manage OAuth with the CARTO 2 platform. This slice is not used with CARTO 3 templates because OAuth is managed through the Auth0 React SDK.

* **Input**:

| Param        | Type     | Description       |
| ------------ | -------- | ----------------- |
| initialState | `Object` | the initial state |

An initial state object might look like:

```jsx
  export const oauthInitialState = {
    oauthApp: {
      clientId: 'YOUR-CARTO-OAUTH-APP-CLIENTID'
      scopes: [
        'user:profile', // to load avatar photo
        'datasets:metadata', // to list all your datasets,
        'dataservices:geocoding', // to use geocoding through Data Services API
        'dataservices:isolines', // to launch isochrones or isodistances through Data Services API
      ],
      authorizeEndPoint: 'https://carto.com/oauth2/authorize',
    }
  };
```

### **setTokenAndUserInfoAsync**

Action to set the userInfo in the redux store, once there is a valid token (and set them both in state).

* **Input**:

| Param | Type     | Description                                                                                    |
| ----- | -------- | ---------------------------------------------------------------------------------------------- |
| props | `Object` | oauthParams, as returned by `useOAuthLogin` hook ({ accessToken, expirationDate, userInfoUrl}) |

* **Example**:

```jsx
import { setTokenAndUserInfoAsync } from "@carto/react-redux";

// const oauthApp = { whatever your app requires... }

const onParamsRefreshed = (oauthParams) => {
  if (oauthParams.error) {
    console.error(`OAuth error: ${oauthParams.error}`);
  } else {
    const action = setTokenAndUserInfoAsync(oauthParams);
    dispatch(action);
  }
};

const [handleLogin] = useOAuthLogin(oauthApp, onParamsRefreshed);

/* 
    oauthParams look something like:
    { 
      accessToken: "xxxxxxxxx", 
      expirationDate: 1616013732973.8652, 
      userInfoUrl: "https://a-certain-user.carto.com/api/v4/me"
    }
  */
```

### **logout**

Action to logout, removing user info & token from redux store.

* **Example**:

```jsx
import { logout } from "@carto/react-redux";

const action = logout();
// dispatch(action)
```

### **selectOAuthCredentials**

Selector to fetch the current OAuth credentials from the redux store.

* **Returns**:

| Param                         | Type     | Description                             |
| ----------------------------- | -------- | --------------------------------------- |
| credentials                   | `Object` | { username, apiKey, serverUrlTemplate } |
| credentials.username          | `string` | CARTO username                          |
| credentials.apiKey            | `string` | apiKey coming from OAuth                |
| credentials.serverUrlTemplate | `string` | required for further api requests       |

* **Example**:

```jsx
import { useSelector } from "react-redux";
import { selectOAuthCredentials } from "@carto/react-redux";

const oauthCredentials = useSelector(selectOAuthCredentials);
```
