- video: https://app.rocketseat.com.br/node/iniciando-o-front-end-web/group/estrutura-das-paginas/lesson/configurando-estrutura-10
- commit: https://github.com/rocketseat-education/bootcamp-gostack-modulos/commit/1b388f960253cf6f9774ab743f30098a2fc4b82e
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>
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
- instructions: https://www.notion.so/ESLint-7e455a7ac78b424892329ee064feaf99#c76fc9ceba6d4944a80c134aa16c61c5
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
It's the same for NodeJS, ReactJS and React Native.
yarn add prettier eslint-config-prettier eslint-plugin-prettier -D
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": {}
}
}
// ...
}
prettier.config.js
module.exports = {
singleQuote: true,
trailingComma: 'es5',
arrowParens: 'avoid',
}
Restart VS Code.
- video: https://app.rocketseat.com.br/node/iniciando-o-front-end-web/group/estrutura-das-paginas/lesson/configurando-estrutura-10
- commit: https://github.com/rocketseat-education/bootcamp-gostack-modulos/commit/3a4dd9321d9836085c024ddaf1442e4888da2511
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;
}
`;
- video: https://app.rocketseat.com.br/node/iniciando-o-front-end-web/group/estrutura-das-paginas/lesson/pagina-de-login-1
- commit: https://github.com/rocketseat-education/bootcamp-gostack-modulos/commit/be6b090021fd44211f30ea591ca638442966b754
- assets: https://xesque.rocketseat.dev/platform/1587470753970-attachment.zip
yarn add reac-icons polished
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``;
-
src/pages/SignIn/index.tsx
with the structure. -
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')};
}
}
`;
- video: https://app.rocketseat.com.br/node/iniciando-o-front-end-web/group/estrutura-das-paginas/lesson/isolando-componentes
- commit: https://github.com/rocketseat-education/bootcamp-gostack-modulos/commit/653903dd9ab96547681738e34bd4512667b328bd
src/components/Input/styles.ts
src/components/Input/index.tsx
src/components/Button/styles.ts
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
fromreact-icons
: link to the source code -
hack to put an icon in an input field:
- put the icon AND the
input
elements inside adiv
- style the
div
as it's an input - style the actual
input
with a transparent background, no border, flex: 1, etc...
- put the icon AND the
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;
}
`;
- video: https://app.rocketseat.com.br/node/iniciando-o-front-end-web/group/estrutura-das-paginas/lesson/pagina-de-cadastro
- commit: https://github.com/rocketseat-education/bootcamp-gostack-modulos/commit/9b89ee0f960ab922e338eeda7e70298bb9f90c70
- assets: https://xesque.rocketseat.dev/platform/1587470786293-attachment.png
Using most of the work done in the SignIn page.
- video: https://app.rocketseat.com.br/node/iniciando-o-front-end-web/group/estrutura-das-paginas/lesson/utilizando-unform-2
- commit: https://github.com/rocketseat-education/bootcamp-gostack-modulos/commit/f06d15629de522bc5d2526443a4d58fa367e722d
yarn add @unform/core @unform/web
-
onFocus
triggers when the element/component gets the focus (duh! pretty obvious). -
onBlur
triggers when the element/component loses the focus. -
Add a property to a
div
(using styled-components + TypeScript):
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 thedependencyArray
changes, therefore if it's an empty array, the function will never be re-rendered. Doc: https://reactjs.org/docs/hooks-reference.html#usecallback
- video: https://app.rocketseat.com.br/node/iniciando-o-front-end-web/group/estrutura-das-paginas/lesson/validando-cadastro
- commit: https://github.com/rocketseat-education/bootcamp-gostack-modulos/commit/5b3f78ff5e2b21038403610e62cb94dfef9056e3
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,
});
-
trick to create an interface with multiple keys:
interface ValidationErrors {
[key: string]: string;
}
-
nice color to mean error:
#c53030
-
a styled component can receive an existing component, but it's important to allow the component to receive
className
in theprops
.