índice.js
index.js será el archivo de entrada de nuestra aplicación web. Aquí, montaremos el componente raíz a un elemento, es decir, a con un id de raíz.
1234567importReactfrom "react";importReactDOMfrom "react-dom";importAppfrom"./App";const rootElement =document.getElementById("root");ReactDOM.render(<App/>, rootElement);
jsx
App.js
En el archivo App.js, hemos definido el componente principal o raíz, es decir, el componente. Vamos a envolver todos los componentes hijos en el componente de la biblioteca react-redux para que el almacén global redux esté disponible en toda la aplicación.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253555657importarReaccionar-de "reaccionar";importar{BrowserRouterasRouter,Switch,Route}de "reaccionar-router-dom";importar". /app.css";import{Proveedor}de "react-redux";import{ applyMiddleware }de "redux";importar reductor de". /reductor";import{ createStore }de "redux";importNavBarfrom"./componentes/Nav";import{Tipografía,Divisor}de"@material-ui/core";importAuthRoutefrom"./componentes/AuthRoute";importHomePagefrom". /pages/HomePage";importLoginPagefrom"./pages/Login";import{ appMiddleware }from"./middlewares/app";import{ apiMiddleware }from"./middlewares/core";importMyAccountfrom". /pages/MyAccount";const createStoreWithMiddleware =applyMiddleware( appMiddleware, apiMiddleware)(createStore);const store =createStoreWithMiddleware(reducer);constIndexPage=()=>(<><Typographyvariant="h3"> >Bienvenido a la App</Typography 10, marginBottom: 10}}/&&;Typographyvariant="h6"`Siéntase libre de echar un vistazo a la App</Typography Providerstore={store};Router=;NavBar/;;divclassName="container"³³³"Switch=;AuthRoutepath="/home "render={HomePage}type="private"/ AuthRoutepath="/login "type="guest"<LoginPage/§;</AuthRoute,|AuthRoutepath="/my-account "type="private jsxFíjese que hemos usado los componentes de react-router-dom para aprovechar el enrutamiento del lado del cliente.
reducer.js
12345678910111213141516171819202122232425262728import{SET_LOADER}from"./actions/ui";import{API_SUCCESS,API_ERROR}from"./actions/api";import{LOGOUT}from". /acciones/auth";exportdefault( state ={ isAuthUser:!!localStorage.getItem("user"), user:JSON.parse(localStorage.getItem("user"))||{}, isLoading:false, error:null}, action)={;switch(action. type){caseAPI_SUCCESS:localStorage.setItem("user",JSON.stringify(action.payload.user));return{...state, isAuthUser:true, user: action.payload.user};caseAPI_ERROR:return{...state, error: action. payload};caseSET_LOADER:return{...state, isLoading: action.payload};caseLOGOUT:localStorage.removeItem("user");return{...state, isAuthUser:false, user:{}};default:return state;}};js
MEDIO AMBIENTE
Crearemos dos tipos de middlewares redux: un appMiddleware y un coreMiddleware. El appMiddeware será responsable de manejar las solicitudes de la API. En este caso, pasamos los datos relevantes para la solicitud de la API a través de la acción LOGIN, y en el coreMiddleware, capturamos la acción API_REQUEST y realizamos la solicitud de red utilizando la biblioteca HTTP axios.
app.js
12345678910111213141516171819202122import{ apiRequest }from"../actions/api";import{LOGIN}from"../actions/auth";constSERVER_URL=`https://61m46.sse.codesandbox. io`;exportconstappMiddleware=()=[[next= ];action=[[next(action);switch(action.type){caseLOGIN:{next(apiRequest({ url:`${SERVER_URL}/login`, method: "POST", data: action.payload}));break;}default:break;}};js
core.js
12345678910111213141516171819202122importar axios de "axios";importar{API_REQUEST, apiError, apiSuccess }de"../acciones/api";importar{ setLoader }de"../acciones/ui";exporttconstapiMiddleware=({ despacho })=[;siguiente==acción={{siguiente(acción);if(acción. type===API_REQUEST){dispatch(setLoader(true));const{ url, method, data }= action.meta;axios({ method, url, data }). then(({ data })= >dispatch(apiSuccess({ response: data }))).catch(error={{console.log(error));dispatch(apiError({ error: error.response.data});});}};js
COMPONENTES
AuthRoute.js
El componente es un componente de orden superior que envuelve el componente de la ruta de reacción para mantener las rutas específicas de nuestra aplicación como privadas o públicas.
1234567891011121314151617importReactfrom "react";import{ connect }from "react-redux";import{Redirect,Route}from "react-router";constAuthRoute=props= {const{ isAuthUser, type }= props;if(type ==="guest"&& isAuthUser)return<Redirectto="/home"/>;elseif(type ==="private"&&! isAuthUser)return<Redirectto="/"/----;;return<Route{...props}/>;};constmapStateToProps=({ isAuthUser })=mph;({ isAuthUser});exportdefaultconnect(mapStateToProps)(AuthRoute);jsx
En el componente, sólo estamos creando el menú de navegación de nuestra aplicación. Noten que he usado el componente de material-ui para darle un aspecto nativo.
1234567891011121314151617181920212223242526272829303132333435363738394041importReact,{Componente}de "react";import{Link}de "react-router-dom";import{AppBar,Toolbar,Button,Typography}de"@material-ui/core";import{ connect }de "react-redux";import{ logout }de". ./actions/auth";classNavBarextendsComponente{render(){retorno(<AppBarposition="static "style={{{{visualizar: "flex"}};toolbar;};Typographyvariant="h6"``Mi App</Tipografía{{N-]divstyle={{{{margenIzquierdo: "auto"}};{esto.props. isAuthUser?(<<Linkto="/home "www.akkrp="herir";Home</Buttoncolor="inherit";Home</Link="Linkto="/mi cuenta";Buttoncolor="herir";Mi cuenta</Buttoncolor="herir "onClick={this.props. logout};Logout};Logout};/Botón (<Linkto="/login"³;³³;Buttoncolor="inherit"³;Login</Button></Link;³;}</div;³³;/Toolbar;³³;/AppBar;³³;}}exportdefaultconnect(({ isAuthUser })={;({ isAuthUser }),{ logout })(NavBar);jsx
PÁGINAS
Login.js
En el archivo Login.js, estamos creando el componente de la página que muestra el formulario de ingreso. Hemos utilizado los modernos ganchos de React para aprovechar el estado en un componente funcional. Esto nos permite hacer el código más preciso y más fácil de mantener.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364importReact,{ useState }de "reaccionar"; import{TextField,Typography,Button}de"@material-ui/core";import{ connect }de "react-redux";import{ login }de". ./actions/auth";importMuiAlertfrom"@material-ui/lab/Alert";functionAlert(props){retorno<MuiAlertelevation={6}variante="filled"{. .. props}/>;}exportdefaultconnect(({ isLoading })=mph;({ isLoading }),{ login })(props=mphmph;{const[email, setEmail]=useState("");const[password, setPassword]=useState(""); const[error, setError]=useState("");constsubmitForm=()= >if(email ===""|| password ===""){setError("Los campos son obligatorios");return;} props. login({ email, password });};return(<form><Typographyvariant="h5 "style={{{{ marginBottom:8}}};Login </Typographyross=;TextFieldlabel="Email "variant="outlined "fullWidthclassName="form-input "value={email}onChange={e=>setEmail(e. target.value)}/><TextFieldlabel="Password "variant="outlined "fullWidthclassName="form-input "type="password "value={password}onChange={e=>setPassword(e. target.value)}/;<Buttonvariant="contained "color="primary "fullWidthclassName="form-input "size="large "onClick={submitForm}{submitForm}; Login </Button error||| error)&&(<Alertseverity="error "onClick={()===setError(null)};{props.error||| error}</Alert>)}</formform;);});jsx