# React Route and Windows

**URL:** <https://forums.docker.com/t/react-route-and-windows/140487>\
**Category:** Docker Desktop\
**Tags:** docker, extension\
**Created:** [March 24, 2024, 8:44pm UTC](https://forums.docker.com/t/react-route-and-windows/140487 "2024-03-24T20:44:29Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![adawkn](https://avatars.discourse-cdn.com/v4/letter/a/919ad9/32.png) [@adawkn](https://forums.docker.com/u/adawkn)\
**Post date:** [March 24, 2024, 8:44pm UTC](https://forums.docker.com/t/react-route-and-windows/140487/1 "2024-03-24T20:44:29Z")

</div>

Hi I’m new to docker and trying to develop an extension as a learning experience. I’m using React Routes to switch between the main pages of the extension but after installing my extension the routing doesn’t seem to be working, nothing renders when I click the buttons that triggers the redirect. I’m working with a few other people and it’s working on their system (Mac) but not on mine(Windows 10).

Let me know if you have any suggestions to get the routing working.

**…Dockerfile…**

```auto
FROM golang:1.19-alpine AS builder
ENV CGO_ENABLED=0
WORKDIR /backend
COPY backend/go.* .
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go mod download
COPY backend/. .
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go build -trimpath -ldflags="-s -w" -o bin/service

FROM --platform=$BUILDPLATFORM node:18.12-alpine3.16 AS client-builder
WORKDIR /ui
# cache packages in layer
COPY ui/package.json /ui/package.json
COPY ui/package-lock.json /ui/package-lock.json
RUN --mount=type=cache,target=/usr/src/app/.npm \
    npm set cache /usr/src/app/.npm && \
    npm ci
# install
COPY ui /ui
RUN npm run build

FROM alpine
LABEL org.opencontainers.image.title="dockular" \
    org.opencontainers.image.description="our osp project" \
    org.opencontainers.image.vendor="danger-noodle-ptri13" \
    com.docker.desktop.extension.api.version="0.3.4" \
    com.docker.extension.screenshots="" \
    com.docker.desktop.extension.icon="" \
    com.docker.extension.detailed-description="" \
    com.docker.extension.publisher-url="" \
    com.docker.extension.additional-urls="" \
    com.docker.extension.categories="" \
    com.docker.extension.changelog=""

COPY --from=builder /backend/bin/service /
COPY docker-compose.yaml .
COPY metadata.json .
COPY docker.svg .
COPY --from=client-builder /ui/build ui
CMD /service -socket /run/guest-services/backend.sock

```

**…Makefile…**

```auto
IMAGE?=my/awesome-extension
TAG?=latest

BUILDER=buildx-multi-arch

INFO_COLOR = \033[0;36m
NO_COLOR = \033[m

build-extension: ## Build service image to be deployed as a desktop extension
	docker build --tag=$(IMAGE):$(TAG) .

install-extension: build-extension ## Install the extension
	docker extension install $(IMAGE):$(TAG)

update-extension: build-extension ## Update the extension
	docker extension update $(IMAGE):$(TAG)

prepare-buildx: ## Create buildx builder for multi-arch build, if not exists
	docker buildx inspect $(BUILDER) || docker buildx create --name=$(BUILDER) --driver=docker-container --driver-opt=network=host

push-extension: prepare-buildx ## Build & Upload extension image to hub. Do not push if tag already exists: make push-extension tag=0.1
	docker pull $(IMAGE):$(TAG) && echo "Failure: Tag already exists" || docker buildx build --push --builder=$(BUILDER) --platform=linux/amd64,linux/arm64 --build-arg TAG=$(TAG) --tag=$(IMAGE):$(TAG) .

help: ## Show this help
	@echo Please specify a build target. The choices are:
	@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(INFO_COLOR)%-30s$(NO_COLOR) %s\n", $$1, $$2}'

.PHONY: help

```

**…main.tsx…**

```auto
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import CssBaseline from "@mui/material/CssBaseline";
import { DockerMuiThemeProvider } from "@docker/docker-mui-theme";

import { App } from './App';

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <BrowserRouter>
    {/*
      If you eject from MUI (which we don't recommend!), you should add
      the `dockerDesktopTheme` class to your root <html> element to get
      some minimal Docker theming.
    */}
    <DockerMuiThemeProvider>
      <CssBaseline />
      <App />
    </DockerMuiThemeProvider>
    </BrowserRouter>
  </React.StrictMode>
);

```

**…App.tsx…**

```auto
import React from 'react';
import { Link } from "react-router-dom"
import { Route, Routes } from "react-router"
import Button from '@mui/material/Button';
import { createDockerDesktopClient } from '@docker/extension-api-client';
import { Divider, Stack, TextField, Typography } from '@mui/material';
import { Metrics } from "./metrics/components/cpu-ram"
import { Prune } from "./prune/prune"

// Note: This line relies on Docker Desktop's presence as a host application.
// If you're running this React app in a browser, it won't work properly.

const App = () => {
  // {"stdout":"{\"BlockIO\":\"7.33MB / 4.1kB\",\"CPUPerc\":\"0.00%\",\"Container\":\"772867bb9f60\",\"ID\":\"772867bb9f60\",\"MemPerc\":\"0.19%\",\"MemUsage\":\"14.9MiB / 7.657GiB\",\"Name\":\"gallant_banzai\",\"NetIO\":\"9.5kB / 0B\",\"PIDs\":\"11\"}\n{\"BlockIO\":\"94.7MB / 21.2MB\",\"CPUPerc\":\"0.51%\",\"Container\":\"f5acb0c87304\",\"ID\":\"f5acb0c87304\",\"MemPerc\":\"2.64%\",\"MemUsage\":\"206.7MiB / 7.657GiB\",\"Name\":\"jovial_mccarthy\",\"NetIO\":\"9.19kB / 0B\",\"PIDs\":\"32\"}\n","stderr":""}
  // const client = createDockerDesktopClient();

  // function useDockerDesktopClient() {
  // return client;
  // }
    const [response, setResponse] = React.useState<string>();
    const ddClient = createDockerDesktopClient();
  
    const fetchAndDisplayResponse = async () => {

    const result = await ddClient.docker.cli.exec("ps", [
      "--all",
      // "--no-trunc",
      "--format",
      '"{{json .}}"',
    ]);

      setResponse(JSON.stringify(result))
  };

  return (
    <>
      <Stack
        direction="row"
        justifyContent="center"
        alignItems="center"
        spacing={8}
        sx= {{ pt : 4, pb : 8}}
      >
        <Typography variant="h3">Test</Typography>
        <Button variant="contained">Home</Button>

        <Button variant="contained">
          <Link to = {'/metrics'}> 
            {'Metrics'}
          </Link>
        </Button>

        <Button variant="contained">
          <Link to = {'/prune'}> 
            {'Prune'}
          </Link>
        </Button>

      </Stack>

      <Routes>
      {/* <Route path ="/" ><h1>Welcome</h1></Route> */}
        <Route path ="/metrics" element = {<Metrics />}/>
        <Route path ="/prune" element = {<Prune />}/>
      </Routes>
    </>
  );
}

export {App}

```

**prune.tsx**

```auto
import React, {useEffect} from 'react';
import Button from '@mui/material/Button';
import { createDockerDesktopClient } from '@docker/extension-api-client';
import { Box, Container } from '@mui/material';
import { blueGrey, red} from '@mui/material/colors';
import { Stack } from "@mui/material";
import { DataGrid, GridRowsProp, GridColDef, gridPageSelector, gridPageCountSelector, useGridApiContext, useGridSelector, } from '@mui/x-data-grid';
import { useGridApiRef } from '@mui/x-data-grid';

const client = createDockerDesktopClient();

function useDockerDesktopClient() {
  return client;
}

export function Prune() {
  const [response, setResponse] = React.useState<string>('dangling-images');
  const [prune, setPrune] = React.useState<string>('');
  //useRef?
  const [containers, setContainers] = React.useState<any[]>([]);

  const ddClient = useDockerDesktopClient();

  //state for grid
  // const apiRef = useGridApiContext();
  // const paginationModel = useGridSelector(apiRef, gridPaginationModelSelector);
  const apiRef = useGridApiRef();
  function testApi(){
    console.log(apiRef.current.getSelectedRows())
  }

  useEffect(()=>{
     if (response === 'dangling-images'){
        //docker images --filter "dangling=true"
        ddClient.docker.cli.exec('images', ['--format', '"{{json .}}"', '--filter', "dangling=true"])
        .then((result) => {
          setContainers(result.parseJsonLines());
        });
    } else {
        ddClient.docker.cli.exec('ps', ['--all', '--format', '"{{json .}}"', '--filter', "status=exited"])
        .then((result) => {
          setContainers(result.parseJsonLines());
        });
    }
  },[response])

  const rows: GridRowsProp = containers.map((image) => ({
    id:image.ID,
    col1:image.Size,
    col2: response === 'dangling-images' ?image.CreatedSince : image.RunningFor,
    col3: response === 'dangling-images' ? image.Tag : image.Status
  }));

  const columns: GridColDef[] = [
    { field: 'id', headerName: 'ID', width: 150 },
    { field: 'col1', headerName: 'Size', width: 150 },
    { field: 'col2', headerName: 'Created', width: 150 },
    { field: 'col3', headerName: response === 'dangling-images'? 'Tag' : 'Status' , width: 150 }
  ];
  
  return (
    <>
        <Container
            sx={{
                width: '95vw',
                height: '85vh',
                bgcolor: blueGrey[50],
                display: 'flex',
                flexDirection: 'column',
                border:2,
                borderColor:'primary.main'

            }}
        >
          <Box 
          sx={{
            width: '90vw',
            height: '40vh',
            bgcolor: blueGrey[50],
            display: 'flex',
            justifyContent:'space-around',
            marginTop:4

        }}>
            <Box 
            sx={{
                bgcolor: blueGrey[50],
                width:'25%', 
                height:'90%',
                borderRadius: 2,
                border:2,
                borderColor:'primary.main'
            }}
            >
            <Stack>
                <Button variant="contained" onClick={()=>{setResponse('dangling-images')}} sx={{
                    m:2,
                    p: 1,
                    borderRadius: 2
                    }}>
                    Dangling Images
                </Button>
                <Button variant="contained" onClick={()=>{setResponse('unused-containers')}} sx={{
                    m:2,
                    p: 1,
                    borderRadius: 2
                }}>
                    UnUsed Containers
                </Button>
            </Stack>
            </Box>

            <Box sx={{
                width:'70%', 
                height:'90%',
                bgcolor: blueGrey[50],
                borderRadius: 2,
                border:2,
                borderColor:'primary.main',
                overflow: 'auto'
                }}>
                <DataGrid rows={rows} columns={columns} checkboxSelection apiRef={apiRef}/>
            </Box>

          </Box>
          <Box sx={{
            width: '90vw',
            height: '40vh',
            bgcolor: blueGrey[50],
            display: 'flex',
            // alignItems:'center',
            justifyContent:'space-around',
            // border:2,
            // borderColor:'primary.main'
            // marginTop:2

        }}>
          <Box
          sx={{
            bgcolor: blueGrey[50],
            width:'25%', 
            height:'90%',
            borderRadius: 2,
            border:2,
            borderColor:'primary.main'
        }}> 
          <Stack>
                <Button variant="contained" color='error' onClick={()=>{setPrune('prune-all')}} sx={{
                    m:2,
                    p: 1,
                    borderRadius: 2
                    }}>
                    Prune All
                </Button>
                
                <Button variant="contained" color='error' onClick={()=>{setPrune('prune-selected')}} sx={{
                    m:2,
                    p: 1,
                    borderRadius: 2
                    }}>
                    Prune Selected
                </Button>
                <Button variant="contained" color='error' onClick={()=>{console.log('Scheduled Prune Pressed'); testApi();}} sx={{
                    m:2,
                    p: 1,
                    borderRadius: 2
                }}>
                    Scheduled Prune
                </Button>
            </Stack>
          </Box>

          <Box
          sx={{
            width:'70%', 
            height:'90%',
            bgcolor: blueGrey[50],
            borderRadius: 2,
            border:2,
            borderColor:'primary.main',
        }}> Chart 
          </Box>
          </Box>
        </Container>
    </>
  );
}

```

---

<div class="post-metadata">

**Author:** ![bluenobly](https://avatars.discourse-cdn.com/v4/letter/b/f9ae1b/32.png) [@bluenobly](https://forums.docker.com/u/bluenobly)\
**Post date:** [March 25, 2024, 5:41pm UTC](https://forums.docker.com/t/react-route-and-windows/140487/2 "2024-03-25T17:41:20Z")

</div>

> [@adawkn](#):
>
> nothing renders when I click the buttons that triggers the redirect

Have you checked with the React Devtools Profiler tool that the components are realy not (re-)rendered?

> <https://stackoverflow.com/questions/41004631/trace-why-a-react-component-is-re-rendering/65425731#65425731>

Are there no error messages in the browser console?
