MaterialUI. El componente App Bar y la propiedad position="fixed"
Tags: react, materialui, navbar
Published: 2024-03-25 23:50:58

En mi proyecto de React, he utilizado el componente App Bar de MaterialUI como barra de navegación. Al emplear `position="fixed"`, el App Bar se mantiene visible en la parte superior de la ventana del navegador, mientras el usuario explora el sitio web.

Ésta propiedad tiene un pequeño detalle, la dimensión del elemento App Bar no afecta al resto de la página. Esto puede causar que alguna parte del contenido sea invisible detrás de la barra de aplicaciones.

Una solución rápida es colocar cualquier elemento, como por ejemplo un "div", que se renderice con la propiedad "height" equivalente a la altura de la App Bar para cubrir éste espacio, es una salida sencilla.

La documentación de MaterialUI brinda tres posibles soluciones también:

[https://mui.com/material-ui/react-app-bar/#fixed-placement](url)



Pero ninguna de éstas soluciones contempla que la App Bar cambie de tamaño, como puede ocurrir en el caso de un diseño responsivo, en donde los elementos se pueden reagrupar dependiendo del espacio disponible. 


![diferencias](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/957gcgo03th1ffu5o8ly.png)


### Propiedad "heigh" dinámica

La solución que desarrollo aquí se lleva a cabo utilizando "Redux" pero se podría hacer utilizando las Props de los componentes.

##### Componente SpaceFixedNavbar.jsx
Creo un componente llamado "SpaceFixedNavbar", será el componente que tomará la propiedad "height" que tenga la App Bar.

```
import React, { useEffect } from "react";
import { useSelector } from "react-redux";

export const SpaceFixedNavbar = () => {
	const navbarHeight = useSelector((state) => state.heightNavBar);

	// useEffect(() => {
	// 	console.log(navbarHeight);
	// }, [navbarHeight]);

	return (
		<div
			style={{
				display: "block",
				width: "100%",
				height: navbarHeight || "56px" ,
				backgroundColor: "#E53170",
			}}></div>
	);
};
```


##### Componente App.jsx
Importo el componente "SpaceFixedNavbar" en el componente App.jsx; que se encargará de renderizarlo en cada componente en donde también se renderice la "NavBar"

```
function App() {
return (
    <>
    <BrowserRouter>
      <SpaceFixedNavbar/>
      <NavBar/>
        <Routes>
          <Route exact path="/" element={<Home/>} />
          <Route path="/AboutUs" element={<AboutUs/>} />
          <Route exact path="/Login" element={<Login/>} />
```

##### Componente NavBar.jsx

En éste componente se utiliza "ResizeObserver" para monitorear el tamaño de la App Bar

```
export default function NavBar() {
	const dispatch = useDispatch();

	const componentRef = useRef(null);

	useEffect(() => {
		handleNavbarHeight(componentRef, dispatch);
	}, []);

	return (
		<AppBar
			position="fixed"
			ref={componentRef}
		>
			{...}
		</AppBar>
	);
}


const handleNavbarHeight = (componentRef, dispatch) => {
	const resizeObserver = new ResizeObserver(entries => {
		if (entries[0]?.target) {
		const newHeight = entries[0].target.offsetHeight;
		// console.log("Nuevo valor de altura:", newHeight);
		dispatch(setHeight(newHeight));
		}
	});

	if (componentRef.current)
		{ resizeObserver.observe(componentRef.current); }

	return () => { resizeObserver.disconnect(); };
};
```
##### Componente heightNavBar.js

Éste es el archivo "action" de Redux. 

```
export const SET_HEIGHT = 'SET_HEIGHT';

export const setHeight = (height) => ({
    type: SET_HEIGHT,
    payload: height,
  });
```

##### Componente RootReducer.js

```
const initialState = {
	{...}
	heightNavBar: 0,
};

const rootReducer = (state = initialState, action) => {
	switch (action.type) {
		{...}

		case SET_HEIGHT:
			return {
				...state,
				heightNavBar: action.payload,
			};

		default:
			return { ...state };
	}
};

export default rootReducer;
```

### Finalizado

Finalmente se puede ver que el componente renderizado adapta su altura de acuerdo a la altura que tiene la NavBar.

![Finalizado](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2vqz0p2d0ovkc8yf1cxx.png)

Ahora que lo he terminado, creo que quedó algo largo para la pequeña funcionalidad que desempeña. Siéntete libre para proponer una solución alternativa más corta en los comentarios. Saludos!