I need to render a map using Mapbox only when data is ready.
I have the following code in my Vuex store:
/store/index.js
import Vue from "vue";
import Vuex from "vuex";
import _ from "lodash";
import { backendCaller } from "src/core/speakers/backend";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
// Activity
activity: [],
geoIps: [],
},
mutations: {
// Activity
setActivity: (state, value) => {
state.activity = value;
},
setGeoIp: (state, value) => {
state.geoIps.push(value);
},
},
actions: {
// Activity
async FETCH_ACTIVITY({ commit, state }, force = false) {
if (!state.activity.length || force) {
await backendCaller.get("activity").then((response) => {
commit("setActivity", response.data.data);
});
}
},
async FETCH_GEO_IPS({ commit, getters }) {
const geoIpsPromises = getters.activityIps.map(async (activityIp) => {
return await Vue.prototype.$axios
.get(
`http://api.ipstack.com/${activityIp}?access_key=${process.env.IP_STACK_API_KEY}`
)
.then((response) => {
return response.data;
});
});
geoIpsPromises.map((geoIp) => {
return geoIp.then((result) => {
commit("setGeoIp", result);
});
});
},
},
getters: {
activityIps: (state) => {
return _.uniq(state.activity.map((activityRow) => activityRow.ip));
},
},
strict: process.env.DEV,
});
In my App.vue I fetch all APIs requests using an async created method.
App.vue:
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: "App",
async created() {
await this.$store.dispatch("FETCH_ACTIVITY");
await this.$store.dispatch("FETCH_GEO_IPS");
},
};
</script>
In my Dashboard component I have a conditional rendering to draw the maps component only when geoIps.length > 0
Dashboard.vue:
<template>
<div v-if="geoIps.length > 0">
<maps-geo-ips-card />
</div>
</template>
<script>
import mapsGeoIpsCard from "components/cards/mapsGeoIpsCard";
export default {
name: "dashboard",
components: {
mapsGeoIpsCard,
},
computed: {
activity() {
return this.$store.state.activity;
},
activityIps() {
return this.$store.getters.activityIps;
},
geoIps() {
return this.$store.state.geoIps;
},
};
</script>
Then I load the Maps component.
<template>
<q-card class="bg-primary APP__card APP__card-highlight">
<q-card-section class="no-padding no-margin">
<div id="map"></div>
</q-card-section>
</q-card>
</template>
<script>
import "mapbox-gl/dist/mapbox-gl.css";
import mapboxgl from "mapbox-gl/dist/mapbox-gl";
export default {
name: "maps-geo-ips-card",
computed: {
geoIps() {
return this.$store.state.geoIps;
},
},
created() {
mapboxgl.accessToken = process.env.MAPBOX_API_KEY;
},
mounted() {
const mapbox = new mapboxgl.Map({
container: "map",
center: [0, 15],
zoom: 1,
});
this.geoIps.map((geoIp) =>
new mapboxgl.Marker()
.setLngLat([geoIp.longitude, geoIp.latitude])
.addTo(mapbox)
);
},
};
</script>
<style>
#map {
height: 500px;
width: 100%;
border-radius: 25px;
overflow: hidden;
}
</style>
The problem is that when the function resolves the first IP address, the map is drawn showing only one address and not all the others like this:
What is the best way to only draw the map when my FETCH_GEO_IPS function has finished?
Thanks in advance
I think the answer lies in this bit of code:
geoIpsPromises.map((geoIp) => {
return geoIp.then((result) => {
commit("setGeoIp", result);
});
});
Your map function loops through every element of the array and commits each IP one by one. So when the first one is committed, your v-if="geoIps.length > 0" is true.
A workaround would be to set a flag only when the IPs are set.
This is a proposed solution:
import Vue from "vue";
import Vuex from "vuex";
import _ from "lodash";
import { backendCaller } from "src/core/speakers/backend";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
// Activity
activity: [],
geoIps: [],
isReady: false
},
mutations: {
// Activity
setActivity: (state, value) => {
state.activity = value;
},
setGeoIp: (state, value) => {
state.geoIps.push(value);
},
setIsReady: (state, value) => {
state.isReady = value;
}
},
actions: {
// Activity
async FETCH_ACTIVITY({ commit, state }, force = false) {
if (!state.activity.length || force) {
await backendCaller.get("activity").then((response) => {
commit("setActivity", response.data.data);
});
}
},
async FETCH_GEO_IPS({ commit, getters }) {
let tofetch = getters.activityIps.length; // get the number of fetch to do
const geoIpsPromises = getters.activityIps.map(async (activityIp) => {
return await Vue.prototype.$axios
.get(
`http://api.ipstack.com/${activityIp}?access_key=${process.env.IP_STACK_API_KEY}`
)
.then((response) => {
return response.data;
});
});
geoIpsPromises.map((geoIp) => {
return geoIp.then((result) => {
commit("setGeoIp", result);
toFetch -= 1; // decrement after each commit
if (toFetch === 0) {
commit("setIsReady", true); // all commits are done
}
});
});
},
},
getters: {
activityIps: (state) => {
return _.uniq(state.activity.map((activityRow) => activityRow.ip));
},
},
strict: process.env.DEV,
});
And in your view:
<template>
<div v-if="isReady">
<maps-geo-ips-card />
</div>
</template>
<script>
import mapsGeoIpsCard from "components/cards/mapsGeoIpsCard";
export default {
name: "dashboard",
components: {
mapsGeoIpsCard,
},
computed: {
activity() {
return this.$store.state.activity;
},
activityIps() {
return this.$store.getters.activityIps;
},
isReady() {
return this.$store.state.isReady;
},
};
</script>
Related
I use vue js version 2.6.11
I have 3 component vue
My first component like this :
<template>
...
<page-listing
:lastPage="lastPage"
:perPage="perPage"
:changePage="changePage"
></page-listing>
</template>
...
</template>
<script>
import { mapActions, mapGetters } from "vuex";
import PageListing from "#/views/app/report/PageListing";
export default {
components: {
"page-listing": PageListing
},
methods: {
...mapActions([
"getReport",
"setPageAction",
]),
searchChange() {
this.loadPage()
},
async changePage(pageNum) {
await this.setPageAction(pageNum)
this.loadPage();
},
loadPage(){
const page = this.page
this.getReport({page});
},
},
computed: {
...mapGetters({
perPage: "reportPerpage",
lastPage: "reportLastPage",
page: "reportPage",
}),
},
mounted() {
this.loadPage();
}
};
</script>
My second component like this :
<template>
...
<div class="card-body">
<p class="mb-0 w-5 w-sm-100">Number</p>
<div class="w-30 w-sm-100">Description</div>
<div class="w-20 w-sm-100">Date</div>
<div class="w-10 w-sm-100">Modified By</div>
</div>
...
<b-row key="list">
<b-colxx xxs="12" v-for="(item,index) in itemsWithLineNumber" :key="index" :id="item.id">
<list-item
:key="item.id"
:data="item"
/>
</b-colxx>
</b-row>
<b-row v-if="lastPage>1">
...
<b-pagination-nav
:number-of-pages="lastPage"
:link-gen="linkGen"
:value="page"
#change="(a)=>changePage(a)"
:per-page="perPage"
align="center"
use-router
>
...
</b-row>
...
</template>
<script>
import { mapActions, mapGetters } from "vuex";
import ListItem from "./ListItem";
export default {
components: {
"list-item": ListItem
},
props: [
"lastPage",
"changePage",
],
methods: {
...mapActions(["setItemsAction"]),
linkGen(pageNum) {
return pageNum === 1 ? '?' : `?page=${pageNum}`
},
},
computed: {
...mapGetters({
perPage: "reportPerpage",
page: "reportPage",
items: "reportItems",
}),
filtered() {
const start = this.page * this.perPage - this.perPage
return this.items.slice(start, start + this.perPage)
},
itemsWithLineNumber() {
return this.filtered.map((item, idx) => {
return {...item, lineNumber: (this.page - 1) * this.perPage + idx + 1}
})
}
}
};
</script>
My three component like this :
<template>
<b-card no-body>
<div class="pl-2 d-flex">
<div class="card-body">
<p class="mb-0 text-muted w-5">{{data.lineNumber}}</p>
<p class="mb-0 text-muted w-30">{{data.description}}</p>
<p class="mb-0 text-muted w-20">{{data.date}}</p>
<p class="mb-0 text-muted w-10">{{data.created_by}}</p>
</div>
</div>
</b-card>
</template>
<script>
export default {
props: ['data'],
}
</script>
My vuex store like this :
const state = {
items: null,
reportError: '',
reportSuccess: '',
page: 1,
perPage: 4,
lastPage: 0,
}
const getters = {
reportError: state => state.reportError,
reportSuccess: state => state.reportSuccess,
reportItems: state => state.items,
reportPage: state => state.page,
reportPerpage: state => state.perPage,
reportLastPage: state => state.lastPage,
}
const mutations = {
getReportSuccess (state, res) {
state.items = res.data
state.perPage = res.meta.per_page;
state.lastPage = res.meta.last_page;
},
getReportError (state, error) {
state.items = null
},
setReportPage (state, payload) {
state.page = payload
},
setPageMutation (state, payload) {
state.page = payload
},
setItemsMutation (state, payload) {
state.items = payload
},
}
const actions = {
getReport ({ commit }, payload) {
...
axios
.get(`${api}/report/list`, { params })
.then(r => r.data)
.then(res => {
if (res.data) {
commit('getReportSuccess', res.data)
} else {
commit('getReportError', 'error:getReport')
}
})
},
setReportPage ({ commit }, payload) {
commit('setReportPage', payload)
},
setPageAction({ commit}, payload) {
commit('setPageMutation', payload)
},
setItemsAction({ commit}, payload) {
commit('setItemsMutation', payload)
},
}
export default {
state,
getters,
mutations,
actions,
}
When the page loads the first time, the line number works and appears. But when I click on the page 2, the page displays blank data
How can I solve this problem?
Please help. Thanks
Update :
Demo like this : https://codesandbox.io/s/prod-hooks-dzk07b
Your problem is with the filtered
filtered() {
const start = this.currentPage * this.perPage - this.perPage;
return this.items.slice(start, start + this.perPage);
},
the items response only has the first n results, when you get rid of them using filter, the array is empty.
you can remove the function and use items result instead
itemsWithLineNumber() {
return this.items.map((item, idx) => {
return {
...item,
lineNumber: (this.currentPage - 1) * this.perPage + idx + 1,
};
});
},
I have 2 inputs in which i provide value to search whether its name of the company, position (1st input) or location (2nd input). It works with one argument provided into foundJobs mutation and then into action. But when payload has an object everything is undefined and array is empty. What am i doing wrong?
component:
<script setup>
import IconSearch from "../Icons/icon-search.vue";
import IconLocation from "../Icons/icon-location.vue";
import { ref } from "vue";
import { useStore } from "vuex";
const store = useStore();
const nameFilter = ref("");
const locationFilter = ref("");
</script>
<template>
<div class="header-filter">
<div class="header-filter__search">
<IconSearch />
<input
type="text"
placeholder="Filter by title, companies, expertise…"
ref="nameFilter"
/>
</div>
<div class="header-filter__location">
<IconLocation />
<input
type="text"
placeholder="Filter by location…"
ref="locationFilter"
/>
</div>
<div class="header-filter__fulltime">
<input type="checkbox" />
<p>Full Time Only</p>
<button
type="button"
#click="
store.dispatch('foundJobs', {
nameFilter: nameFilter.value,
locationFilter: locationFilter.value,
})
"
>
Search
</button>
</div>
</div>
</template>
vuex: (not working)
import { createStore } from "vuex";
const store = createStore({
state() {
return {
jobs: [],
filteredJobs: [],
};
},
mutations: {
setJobs(state, jobs) {
state.jobs = jobs;
},
foundJobs(state, { nameInputValue, locationInputValue }) {
let copiedJobsArr = [...state.jobs];
if (nameInputValue !== "") {
copiedJobsArr = copiedJobsArr.filter(
(job) =>
job.company === nameInputValue || job.position === nameInputValue
);
}
if (locationInputValue !== "") {
copiedJobsArr = copiedJobsArr.filter(
(job) => job.location === locationInputValue
);
}
console.log(locationInputValue); // undefined
state.filteredJobs = copiedJobsArr;
console.log(state.filteredJobs); //empty array
},
},
actions: {
foundJobs(context, { nameInputValue, locationInputValue }) {
context.commit("foundJobs", { nameInputValue, locationInputValue });
},
loadJobs(context) {
return fetch("./data.json")
.then((response) => {
return response.json();
})
.then((data) => {
const transformedData = data.map((job) => {
return {
id: job.id,
company: job.company,
logo: job.logo,
logoBackground: job.logoBackground,
position: job.position,
postedAt: job.postedAt,
contract: job.contract,
location: job.location,
website: job.website,
apply: job.apply,
description: job.description,
reqContent: job.requirements.content,
reqItems: job.requirements.items,
roleContent: job.role.content,
roleItems: job.role.items,
};
});
context.commit("setJobs", transformedData);
});
},
},
getters: {
jobs(state) {
return state.jobs;
},
filteredJobOffers(state) {
return state.filteredJobs;
},
},
});
export default store;
vuex (working) - here i also provide one argument into action assigned to a button (in a component file)
import { createStore } from "vuex";
const store = createStore({
state() {
return {
jobs: [],
filteredJobs: [],
};
},
mutations: {
setJobs(state, jobs) {
state.jobs = jobs;
},
foundJobs(state, nameInputValue) {
let copiedJobsArr = [...state.jobs];
if (nameInputValue !== "") {
copiedJobsArr = copiedJobsArr.filter(
(job) =>
job.company === nameInputValue || job.position === nameInputValue
);
}
console.log(nameInputValue);
state.filteredJobs = copiedJobsArr;
console.log(state.filteredJobs);
},
},
actions: {
foundJobs(context, nameInputValue) {
context.commit("foundJobs", nameInputValue);
},
loadJobs(context) {
return fetch("./data.json")
.then((response) => {
return response.json();
})
.then((data) => {
const transformedData = data.map((job) => {
return {
id: job.id,
company: job.company,
logo: job.logo,
logoBackground: job.logoBackground,
position: job.position,
postedAt: job.postedAt,
contract: job.contract,
location: job.location,
website: job.website,
apply: job.apply,
description: job.description,
reqContent: job.requirements.content,
reqItems: job.requirements.items,
roleContent: job.role.content,
roleItems: job.role.items,
};
});
context.commit("setJobs", transformedData);
});
},
},
getters: {
jobs(state) {
return state.jobs;
},
filteredJobOffers(state) {
return state.filteredJobs;
},
},
});
export default store;
store.dispatch('foundJobs', {
nameFilter: nameFilter.value,
locationFilter: locationFilter.value,
})
You are sending data like this and trying to get on the wrong way
foundJobs(state, { nameInputValue, locationInputValue })
you can receive data this way:
foundJobs(state, { nameFilter, locationFilter})
After reading the official xstate tutorial, I tried to implement my own machine inspired by this post on dev.to by one of the xstate's dev.
Everything works as expected besides that output does not seem to be updated. The assignment does not do its job I think. What did I forget?
To compare, here is a working demo from xstate where the variable in the context is updated as expected.
more information on assign on Context | XState Docs
my code:
import "./styles.css";
import * as React from "react";
import * as ReactDOM from "react-dom";
import { createMachine, assign } from "xstate";
import { useMachine } from "#xstate/react";
interface FetchContext {
output: string;
}
const fetchifetch = async () => {
return await fetch(
"https://jsonplaceholder.typicode.com/todos/1"
).then((response) => response.json());
};
const fetchMachine = createMachine<FetchContext>({
initial: "idle",
context: {
output: "wesh" // none selected
},
states: {
idle: {
on: {
FETCH: "loading"
}
},
loading: {
invoke: {
src: (context, event) => async (send) => {
setTimeout(async () => {
const data = await fetchifetch();
console.log("done");
console.log(data);
// well. here I want to assign something to output
assign({
output: (context, event) => data.title
});
send("FETCHED_SUCCESSFULLY");
}, 4000);
console.log("start");
},
onError: {
target: "idle"
}
},
on: {
FETCHED_SUCCESSFULLY: {
target: "idle"
}
}
},
fetch: {
on: {
CLOSE: "idle"
}
}
}
});
function App() {
const [current, send] = useMachine(fetchMachine);
const { output } = current.context;
return (
<div className="App">
<h1>XState React Template</h1>
<br />
<input
disabled={current.matches("loading")}
defaultValue="yo"
onChange={(e) => console.log(e.currentTarget.value)}
/>
<button
disabled={current.matches("loading")}
onClick={() => send("FETCH")}
>
click to fetch
</button>
<!-- let's display the result over here -->
<div>{output}</div>
<div>{current.context.output}</div>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
You need to return a Promise then and have the state machine update the context after the Promise is resolved.
The context is updated in the onDone property of invoke.
const fetchMachine = createMachine<FetchContext>({
initial: "idle",
context: {
output: "wesh" // none selected
},
states: {
idle: {
on: {
FETCH: "loading"
}
},
loading: {
invoke: {
src: (context, event) => async (send) => {
return new Promise((resolve, reject) => {
setTimeout(async () => {
try {
const data = await fetchifetch();
resolve(data.title);
} catch (err) {
reject(err);
}
}, 4000);
});
},
onDone: {
target: "fetch",
actions: assign({
output: (_, event) => event.data,
})
},
onError: {
target: "idle"
}
},
on: {
FETCHED_SUCCESSFULLY: {
target: "idle",
}
}
},
fetch: {
on: {
CLOSE: "idle"
}
}
}
});
I’m new to Vue and I’m developing a map application with vue2-leaflet. I would like to add a search box to my application to locate markers on my map, I found this leaflet plugin leaflet-search which is just the functionality I’m looking for, but I don’t know how to integrate it into my vue cli project.
After installing the plugin, how do I import it into my vue component? and, where in my <script> should I add the code?
This is what the component where I want to add the search box looks like:
<template>
<body>
<l-map class="map" ref="map" :min-zoom="minZoom" :crs="crs">
<l-tile-layer :url="url"></l-tile-layer>
<l-grid-layer class="grid" :tile-component="tileComponent"></l-grid-layer>
<l-marker v-for="(newCoords, i) in InvertedCoords" :key="i" :lat-lng="newCoords">
<div v-if="stars[i].status === 'ALLY'">
<l-icon ></l-icon>
</div>
<div v-else>
<l-icon></l-icon>
</div>
<l-popup class="popup">
<em class="popup-bold">Name: </em>{{ stars[i].name }}<br />
<em class="popup-bold">Longitud: </em>{{ stars[i].lng }}<br />
<em class="popup-bold">Latitud: </em>{{ stars[i].lat }}<br />
</l-popup>
</l-marker>
</l-map>
</body>
</template>
<script>
import L from "leaflet";
import { CRS } from "leaflet";
import GridTemplate from './GridTemplate.vue';
import { eventBus } from '../main.js'
import {
LMap,
LTileLayer,
LMarker,
LPopup,
LPolyline,
LIcon,
} from "vue2-leaflet";
export default {
name: "Map",
components: {
LMap,
LTileLayer,
LMarker,
LImageOverlay,
LPopup,
LIcon,
},
props: {
msg: {
type: String
}
},
data() {
return {
url: "",
bounds: [ [-2600, -2700], [1000, 3000] ],
minZoom: 0,
crs: L.CRS.Simple,
stars: [],
messageList: [],
tileComponent: GridTemplate
};
},
computed: {
InvertedCoords() {
var newArraw = [];
for (let i = 0; i < this.stars.length; i++) {
newArraw[i] = {
id: i + 2,
lat: this.stars[i].lat * -1,
lng: this.stars[i].lng * -1
};
}
return newArraw;
console.log(newArraw);
}
},
watch: {
msg: function() {
this.messageList.push(this.msg);
}
},
mounted() {
this.$refs.map.mapObject.setView([552, 40], 1);
this.$http.get("url")
.then(response => {
return response.json();
})
.then(data => {
const resultArray = [];
for (let key in data) {
resultArray.push(data[key]);
}
this.stars = resultArray;
});
methods: {
inverted() {
for (let i = 0; i < this.newArraw.length; i++) {
console.log(this.newArraw[i]);
return this.newArraw[i];
}
},
updateStars(text) {
this.$http.get("url")
.then(response => {
return response.json();
})
.then(data => {
const resultArray = [];
for (let key in data) {
resultArray.push(data[key]);
}
this.stars = resultArray;
});
},
StarsData() {
eventBus.$emit('i-got-clicked', this.stars)
},
}
};
</script>
<style scoped>
</style>
I don't know your Plugin but I have used gesearch.
Here is what I did to register the leaflet plugin.
import { OpenStreetMapProvider } from "leaflet-geosearch";
import "leaflet-geosearch/assets/css/leaflet.css";
import { GeoSearchControl } from "leaflet-geosearch";
Then in mounted() I can register it to leaflet. You can look at the docs of how to register controls.
mounted() {
const map = this.$refs.map.mapObject;
const searchControl = new GeoSearchControl({
provider,
// ... some more options
});
map.addControl(searchControl);
}
Perhaps this helps you.
I have an app which has multiple stack navigators, one of which has a createMaterialTopTabNavigator inside it which shows me a list. Now for each of the tabs i get a count of the items inside it, i fetch these count through a separate API call (Count for all tabs is fetched through a single API). By default i am able to show a static tabLabel.
What i need to do is to show the count of each of the tabs in their labels(tab titles).
Navigator Code:
import React from "react";
import { View } from "react-native";
import { createMaterialTopTabNavigator } from "react-navigation";
import SellerListingScreen from "screens/App/SellerListingScreen/SellerListingScreen";
const SellerListingNavigator = createMaterialTopTabNavigator(
{
PendingSellers: {
screen: () => <SellerListingScreen type={0} />,
navigationOptions: {
title: "Pending(<show count here>)"
}
},
CompletedSellers: {
screen: () => <SellerListingScreen type={1} />,
navigationOptions: {
title: "Completed(<show count here>)"
}
}
},
{
tabBarOptions: {
style: {
backgroundColor: "#00cc99"
}
},
lazy: true
}
);
export default SellerListingNavigator;
With react-navigation, navigationOptions can be a static object like in your current example or a function that take an object containing the navigation object. In your case, you can easily rewrite your navigationOptions like this:
({navigation}) => {
const fetchDone = navigation.getParam('countFetchDone');
const currentCount = navigation.getParam('count');
if (!fetchDone) {
navigation.setParam('countFetchDone', true);
fetch(YOUR_FETCH_OPTIONS_HERE)
.then((r) => r.json())
.then((data) => {
navigation.setParam('count', data.count);
});
}
if (currentCount !== undefined) {
return {
title: 'My list (' + currentCount + ')'
};
} else {
return {
title 'My list (...)'
};
}
}
You need to save the state of the query as params so that the header updates correctly (as it updates only when params change). fetchDone is used to be sure the query is done once.
Ok i managed to solve it by creating a custom navigator white extending my existing tabNavigator & passing the required params to screenProps
import React from "react";
import { createMaterialTopTabNavigator } from "react-navigation";
// #ts-ignore
import SellerListingScreen from "screens/App/SellerListingScreen/SellerListingScreen";
// #ts-ignore
import { getItem } from "utils/interactAsyncStorage";
const SellerListingNavigator = createMaterialTopTabNavigator(
{
PendingSellers: {
screen: () => <SellerListingScreen type={0} />,
navigationOptions: ({ screenProps }) => ({
title: `Pending (${screenProps.pending})`
})
},
CompletedSellers: {
screen: () => <SellerListingScreen type={1} />,
navigationOptions: ({ screenProps }) => ({
title: `Completed (${screenProps.completed})`
})
}
},
{
tabBarOptions: {
style: {
backgroundColor: "#00cc99"
}
},
lazy: true
}
);
class customSellerListingNavigator extends React.Component {
constructor(props) {
super(props);
this.state = { pending: 0, completed: 0 };
}
static router = SellerListingNavigator.router;
_fetchPickupCounts = async () => {
const userData = await getItem("UserData");
const headers = {
"Content-Type": "application/json",
"Session-Token": userData.sessionToken,
};
const baseUrl = "baseurl here";
const url = `${baseUrl}/pickupCount/`;
return await fetch(url, {
method: "post",
headers: headers
})
.then(response => response.json())
.then(responseJson => {
this.setState({
pending: responseJson.pending,
completed: responseJson.completed
});
})
.catch(error => {
console.error(error);
});
};
componentDidMount() {
this._fetchPickupCounts();
}
render() {
const { navigation } = this.props;
return (
<SellerListingNavigator
navigation={navigation}
screenProps={{
pending: this.state.pending,
completed: this.state.completed
}}
/>
);
}
}
export default customSellerListingNavigator;