- fullstackopen-Course-and-testing
- Part 1. Introduction to React
- Part 2. Communicating with server
- Part 5. Testing React apps
- Part 6. Flux-architexture and Redux
- Part 7. React router, custom hooks, styling app with CSS and webpack
- a. React Router (v5)
- b. Custom hooks
- Prototipo de hook para realizar peticiiones fetch con axios que se pueden usar en cualquier aplicación. Solo hay que actualizar
baseURL
y eltoken
: - c. React Bootstrap
- Material UI
- Ejecutar un servidor local para archivos estáticos. Ejecutar este comando en el directorio con el index:
- Algunos comandos útiles
- Seguridad
- Instalar y configurar prettier:
- Part 9. TypeScript
- Part 11. Continuous Integration / Continuous Delivery systems (CI/CD)
- Part 12. Containers
- Part 12. Using relational databases
npm create vite@latest
cd <install-dir>
npm install
npm run dev
- Component
- Multiple components
- props: passing data to components
- Possible error message
- Do not render objects
Node.js is a JavaScript runtime environment based on Google's Chrome V8 JavaScript engine and works practically anywhere - from servers to mobile phones. The latest versions of Node already understand the latest versions of JavaScript, so the code does not need to be transpiled.
The contents of the array can be modified even though it is defined as a const
. Because the array is an object, the variable always points to the same object. However, the content of the array changes as new items are added to it.
const t = [1, -1, 3]
t.push(5) //[1, -1, 3, 5]
const t2 = t.concat(5) //t2 = [1, -1, 3, 5]
// destructuring assignment
const t = [1, 2, 3, 4, 5]
const [first, second, ...rest] = t
console.log(first, second) // 1, 2 is printed
console.log(rest) // [3, 4, 5] is printed
t.forEach((value) => {
console.log(value) // numbers 1, -1, 3, 5 are printed, each on its own line
})
const m2 = t.map((value) => '<li>' + value + '</li>')
console.log(m2)
// [ '<li>1</li>', '<li>2</li>', '<li>3</li>' ] is printed
const sum = (p1, p2) => {
console.log(p1)
console.log(p2)
return p1 + p2
}
const result = sum(1, 5)
console.log(result)
// If there is just a single parameter, we can exclude the parentheses from the definition:
const square = (p) => {
console.log(p)
return p * p
// If the function only contains a single expression then the braces are not needed.
const square = (p) => p * p
const t = [1, 2, 3]
const tSquared = t.map((p) => p * p)
// tSquared is now [1, 4, 9]
// There are two ways to reference the function; one is giving a name in a function declaration.
function product(a, b) {
return a * b
}
const result = product(2, 6)
// result is now 12
//The other way to define the function is by using a function expression.
const average = function (a, b) {
return (a + b) / 2
}
const result = average(2, 5)
// result is now 3.5
}
const arto = {
name: 'Arto Hellas',
age: 35,
education: 'PhD',
greet: function () {
console.log('hello, my name is ' + this.name)
},
doAddition: function (a, b) {
console.log(a + b)
},
}
arto.doAddition(1, 4) // 5 is printed
const referenceToAddition = arto.doAddition
referenceToAddition(10, 15) // 25 is printed
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
greet() {
console.log('hello, my name is ' + this.name)
}
}
const adam = new Person('Adam Ondra', 35)
adam.greet()
const janja = new Person('Janja Garnbret', 22)
janja.greet()
https://fullstackopen.com/en/part1/java_script#classes
- Mozilla's JavaScript Guide
- A re-introduction to JavaScript (JS tutorial)
- You-Dont-Know-JS
- javascript.info
- book Eloquent JavaScript
- Namaste 🙏 JavaScript
- Chrome V8
- Console JS Tools online
- Arrow functions
- Understand JavaScript's this Keyword in Depth
- Classes in JS
- Component helper functions
- Destructuring
- Stateful component
- Event handling
- An event handler is a function
- Passing state - to child components
- Refactoring the components
- Complex state
- Handling arrays
- Conditional rendering
- A function that returns a function
- Do Not Define Components Within Components
It is forbidden in React to mutate state directly, since it can result in unexpected side effects
There are situations where it can be beneficial to store a piece of application state in a more complex data structure: https://react.dev/learn/choosing-the-state-structure
https://fullstackopen.com/en/part1/a_more_complex_state_debugging_react_apps#useful-reading
Full stack development is extremely hard, that is why I will use all the possible means to make it easier:
- I will have my browser developer console open all the time
- I will use the network tab of the browser dev tools to ensure that frontend and backend are communicating as I expect
- I will constantly keep an eye on the state of the server to make sure that the data sent there by the frontend is saved there as I expect
- I will keep an eye on the database: does the backend save data there in the right format
- I progress with small steps:
- when I suspect that there is a bug in the frontend, I make sure that the backend works for sure
- when I suspect that there is a bug in the backend, I make sure that the frontend works for sure
- I will write lots of console.log statements to make sure I understand how the code and the tests behave and to help pinpoint problems
- If my code does not work, I will not write more code. Instead, I start deleting the code until it works or just return to a state when everything still was still working
- If a test does not pass, I make sure that the tested functionality for sure works in the application
npm install json-server --save-dev
npx json-server --port 3001 --watch db.json
In http://localhost:3001/notes will be the notes.
Plugin to browser JSONVue
- Install
axios
npm install axios
- Sending Data to the Server
- Changing the Importance of Notes
- Extracting Communication with the Backend into a Separate Module
- Cleaner Syntax for Defining Object Literals
- Promises and Errors
// Primer terminal para ejecutar el backend nodeJS (part4)
cd part5/backend
npm run dev
// En un segundo terminal abierto para ejecutar react (part5 a partir de part2)
cd part5
npm run dev
- Handling login Ver: login.js y notes.js
- Creating new notes
- Saving the token to the browser's local storage
- Displaying the login form only when appropriate
- The components children, aka. props.children
- State of the forms
- References to components with ref
- PropTypes
npm install prop-types
npm install --save-dev eslint-plugin-jest
See .eslintrc.cjs file and .eslintignore
Install libraries (react-testing-library):
npm install jest babel-jest @babel/preset-env @babel/preset-react
npm install --save-dev @testing-library/react @testing-library/jest-dom jest-environment-jsdom @babel/preset-env @babel/preset-react
npm install --save-dev @testing-library/user-event
Extra configuration with vite.
- Rendering the component for tests
- Searching for content in a component
- Debugging tests
- Clicking buttons in tests
- Tests for the Togglable component
- Testing the forms
- About finding the elements
Install Cypress
:
npm install --save-dev cypress
npm install eslint-plugin-cypress --save-dev
Execute backend in test mode: cd backend && npm run start:test
and frontend: npm run dev
. Also in an additional terminal with cypress: npm run cypress:open
- Cypress
- Testing new note form
- Controlling the state of the database
- Failed login test
- Bypassing the UI
- Changing the importance of a note
npm create vite@latest
cd <install-dir>
npm install
npm run dev
npm install redux
npm install redux
npm install --save-dev jest @babel/preset-env @babel/preset-react eslint-plugin-jest
// add the library deep-freeze, which can be used to ensure that the reducer has been correctly defined as an immutable function
npm install --save-dev deep-freeze
Install test libraries and configuration
npm install redux
npm install @reduxjs/toolkit
console.log(JSON.parse(JSON.stringify(state)))
- Managing data on the server with the React Query library
npm install @tanstack/react-query
- Synchronizing data to the server using React Query
- useReducer | Example
- useContext - Using context for passing the state to components | Example
- useContext - Defining the counter context in a separate file| Example
Install react router:
npm install react-router-dom
See example using react Router, and the hooks useNavigate, useParams and useMatch here
Let's define our own custom useField
hook that simplifies the state management of the form:
const useField = (type) => {
const [value, setValue] = useState('')
const onChange = (event) => {
setValue(event.target.value)
}
return {
type,
value,
onChange,
}
}
The hook can be used in the following way:
const App = () => {
const name = useField('text')
// ...
return (
<div>
<form>
<input type={name.type} value={name.value} onChange={name.onChange} />
// ...
</form>
</div>
)
}
Or with Spread attributes
:
const App = () => {
const name = useField('text')
// ...
return (
<div>
<form>
<input {...name} />
// ...
</form>
</div>
)
}
As the example in the React documentation states, the following two ways of passing props to a component achieve the exact same result:
<Greeting firstName='Arto' lastName='Hellas' />
const person = {
firstName: 'Arto',
lastName: 'Hellas'
}
<Greeting {...person} />
Prototipo de hook para realizar peticiiones fetch con axios que se pueden usar en cualquier aplicación. Solo hay que actualizar baseURL
y el token
:
import axios from 'axios'
const baseUrl = '/api/notes'
let token = null
const setToken = (newToken) => {
token = `bearer ${newToken}`
}
const getAll = async () => {
const response = await axios.get(baseUrl)
return response.data
}
const create = async (newObject) => {
const config = {
headers: { Authorization: token },
}
const response = await axios.post(baseUrl, newObject, config)
return response.data
}
const update = async (id, newObject) => {
const response = await axios.put(`${baseUrl}/${id}`, newObject)
return response.data
}
export default { getAll, create, update, setToken }
Hay algunas versiones diferentes de React de Bootstrap como reactstrap y react-bootstrap.
Instalar react-bootstrap:
npm install react-bootstrap
Agregar en la sección del head
en el archivo public/index.html
:
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65"
crossorigin="anonymous"
/>
Código de ejemplo aquí.
Fuente: https://mui.com/
Instalar la librería:
npm install @mui/material @emotion/react @emotion/styled
Código de ejemplo aquí.
Ejecutar un servidor local para archivos estáticos. Ejecutar este comando en el directorio con el index:
npx static-server
Puede verificar qué tan actualizadas están sus dependencias usando el comando:
npm outdated --depth 0
Las dependencias se pueden actualizar actualizando el archivo package.json
y ejecutando el comando:
npm install -g npm-check-updates
npm-check-updates
El archivo package.json se actualiza ejecutando el comando ncu -u
y npm install
.
Para revisar dependencias con problemas de seguridad (npm audit
) y hacer las correcciones: npm audit fix
. El comando npm audit fix --force
puede determinar en actualizaciones major que pueden colapsar la aplicación.
La documentación de Express incluye una sección sobre seguridad: Prácticas recomendadas de producción: seguridad, que vale la pena leer. También se recomienda agregar una librería llamada Helmet al backend. Incluye un conjunto de middlewares que eliminan algunas vulnerabilidades de seguridad en aplicaciones Express.
También vale la pena usar el plugin de seguridad de ESlint.
npm install --save-dev --save-exact prettier
node --eval "fs.writeFileSync('.prettierrc','{\n\"trailingComma\": \"none\",\n\"tabWidth\": 2,\n\"semi\": false,\n\"singleQuote\": true,\n\"editor.formatOnSave\": true\n}\n')"
node --eval "fs.writeFileSync('.prettierignore','build\ncoverage')"
Fuente: https://prettier.io/docs/en/install