Skip to content

Latest commit

 

History

History
400 lines (310 loc) · 10.5 KB

02.1-frontend-pages.md

File metadata and controls

400 lines (310 loc) · 10.5 KB

React - Pages Structure

Starting the Project

npx create-react-app gobarber-web --template=typescript
cd gobarber-web
rm README.md
cd src
rm App.css App.test.tsx index.css logo.svg serviceWorker.ts
# remove the references to the deleted files in index.tsx and App.tsx
# write an React.FC with a 'Hello World' in the App.tsx
cd ../public
rm favicon.ico logo192.png logo512.png manifest.json
# remove the references to the deleted files in index.html

public/index.html:

<meta name="theme-color" content="#3a3a3a" />
<title>GoBarber</title>

Editor Config

root = true

[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf

ESLint

Assuming the project was created with create-react-app.

In the package.json REMOVE this part:

"eslintConfig": {
  // ...
},

Install eslint and initialize it:

yarn add eslint
yarn eslint --init
# 1. To check syntax, find problems and enforce code style
# 2. JavaScript modules (impot/export)
# 3. React
# 4. (use TypeScript?) Yes
# 5. (mark only Browser with space bar and then Enter)
# 6. Use a popular style guide
# 7. Airbnb
# 8. JSON
# 9. (install with npm?) No

# copy the packages shown on the question 9 except 'eslint@^5.16.0 || ^6.8.0'
# because we already have it, and remove 1.7.0 from
# 'eslint-plugin-react-hooks@^2.5.0 || ^1.7.0'. The command will become like this:
yarn add -D eslint-plugin-react@^7.19.0 @typescript-eslint/eslint-plugin@latest eslint-config-airbnb@latest eslint-plugin-import@^2.20.1 eslint-plugin-jsx-a11y@^6.2.3 eslint-plugin-react-hooks@^2.5.0 @typescript-eslint/parser@latest

# making ReactJS undertand TypeScrpt
yarn add -D eslint-import-resolver-typescript -D

Create the .eslingignore file:

/*.js
**/*.js
node_modules
build
/src/react-app-env.d.ts

Prettier

It's the same for NodeJS, ReactJS and React Native.

yarn add prettier eslint-config-prettier eslint-plugin-prettier -D

.eslintrc.json

Edit .eslintrc.json:

{
  // ...
  "extends": [
    "plugin:react/recommended"
    "plugin:@typescript-eslint/recommended",
    "prettier/@typescript-eslint",
    "plugin:prettier/recommended",
  ],
  // ...
  "plugins": [
    // ...
    "react-hooks",
    "@typescript-eslint",
    "prettier"
  ],
  "rules": {
    "prettier/prettier": "error",
    "no-use-before-define": "off",
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn",
    "import/prefer-default-export": "off",
    "import/extensions": [
      "error",
      "ignorePackages",
      {
        "ts": "never",
        "tsx": "never"
      }
    ]
  },
  // ...
  "settings": {
    "import/resolver": {
      "typescript": {}
    }
  }
  // ...
}

Solving conflicts between ESLint and Prettier.

prettier.config.js

module.exports = {
  singleQuote: true,
  trailingComma: 'es5',
  arrowParens: 'avoid',
}

Restart VS Code.

Global Styles

src/styles/globals.ts:

import { createGlobalStyle } from 'styled-components';

export default createGlobalStyle`
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    outline: 0;
  }

  body {
    background: #312e38;
    color: #fff;
  }

  body , input , button {
    font-family: 'Roboto Slab', serif;
    font-size: 16px;
  }

  h1, h2, h3, h4, h5, h6, strong {
    font-weight: 500;
  }

  button {
    cursor: pointer;
  }
`;

Login Page

yarn add reac-icons polished
  1. src/pages/SignIn/styles.ts just with declarations.
import styled from 'styled-components';

export const Container = styled.div``;
export const Content = styled.div``;
export const Background = styled.div``;
  1. src/pages/SignIn/index.tsx with the structure.

  2. Finish src/pages/SignIn/styles.ts.

  • trick for a smooth transition when hovering a button (using polished to make the color a little darker):
import { shade } from 'polished';

// ...

export const Content = styled.div`
  button {
    transition: background-color 0.2s;

    &:hover {
      background: ${shade(0.2, '#ff9000')};
    }
  }
`;

Isolating Components

  1. src/components/Input/styles.ts
  2. src/components/Input/index.tsx
  3. src/components/Button/styles.ts
  4. src/components/Button/index.tsx

The src/components/Input/index.tsx deserves some comments:

import React, { InputHTMLAttributes } from 'react';
import { IconBaseProps } from 'react-icons';

import { InputContainer } from './styles';

interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
  name: string;
  icon?: React.ComponentType<IconBaseProps>;
  // - React.ComponentType: allows a component to receive another component
  // as a property.
  // - IconBaseProps: it's a way to have access to the icon's properties.
}

const Input: React.FC<InputProps> = ({ icon: Icon, ...rest }) => (
  <InputContainer>
    {Icon && <Icon size={20} />}
    <input {...rest} type="text" />
  </InputContainer>
);

export default Input;
  • React.ComponentType: allows a component to receive another component as a prop.

  • IconBaseProps from react-icons: link to the source code

  • hack to put an icon in an input field:

    • put the icon AND the input elements inside a div
    • style the div as it's an input
    • style the actual input with a transparent background, no border, flex: 1, etc...
import styled from 'styled-components';

export const InputContainer = styled.div`
  background: #232129;
  border-radius: 10px;
  border: 2px solid #232129;
  padding: 16px;
  color: #666360;
  width: 100%;

  display: flex;
  align-items: center;

  & + div {
    margin-top: 8px;
  }

  input {
    flex: 1;
    background: transparent;
    border: 0;
    color: #f4ede8;

    &::placeholder {
      color: #666360;
    }
  }

  svg {
    margin-right: 16px;
  }
`;

Sign Up Page

Using most of the work done in the SignIn page.

Using Unform

yarn add @unform/core @unform/web

Input Usability

interface ContainerProps {
  isFocused: boolean
}

export const Container = styled.div<ContainerProps>``;
  • useCallback(function, dependencyArray): useful when declaring a function inside another function. Prevents unnecessary renders. It'll only re-render if an element in the dependencyArray changes, therefore if it's an empty array, the function will never be re-rendered. Doc: https://reactjs.org/docs/hooks-reference.html#usecallback

Validating Input

yarn add yup
yarn add -D @types/yup
  • Building a Yup schema:
import * as Yup from 'yup';
// ...

const schema = Yup.object().shape({
  name: Yup.string().
    required('Nome obrigatório'),
  email: Yup.string()
    .required('Email obrigatório')
    .email('Digite um email válido'),
  password: Yup.string()
    .min(6, 'Senha de no mínimo 6 caracteres'),
});
await schema.validate(data, {
  abortEarly: false,
});

Showing the Validation Errors

interface ValidationErrors {
  [key: string]: string;
}

Creating Errors' Tooltips

Validating Login