Reactjs
Reactjs
Reactjs Training Materials
Copyright Notice
Copyright © 2004-2025 by NobleProg Limited All rights reserved.
This publication is protected by copyright, and permission must be obtained from the publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission in any form or by any means, electronic, mechanical, photocopying, recording, or likewise.
Introduction
- Developed by engineers at Facebook
- "A JavaScript library for building user interfaces"
- React enables websites to display
- Complex animations
- Large volumes of data
- Other memory-heavy tasks without slowing down
Intro Con't
- Declarative
- Component-Based
- Reusable and independent
Declarative
- Declarative views make the code more predictable and easier to debug
- Very easy way to create interactive UIs
- Simple views for each state in the application
- Efficient update and render of the right components when the data changes
Component-Based
- Encapsulated components that manage their own state
- Compose them to make complex UIs
- Component logic is written in JavaScript instead of templates
- Easy to pass rich data through the app
- In the same time keeps state out of the DOM
Reusable
- Independent from technology stack used in the whole project
- We can develop new features without rewriting existing code
- Can render on the server (for example using Nodejs)
- Can power mobile apps using React Native
Design principles behind React
- JSX
- Rendering Elements
- Components and props
JSX
- Is not valid JavaScript (web browsers can't read it)
- Syntax extension for JavaScript
- Was written to be used with React
- JSX code looks a lot like HTML
const h1 = <h1>Hi universe</h1>;
- Also XML-like
- Have to be compiled into regular JavaScript
- Is optional and not required to use in React
- https://react.dev/learn/writing-markup-with-jsx
Rendering Elements
- The smallest building block of React apps
- Rendering an element into the DOM
- Updating the rendered element
- Updated will be only that what's necessary
- https://react.dev/learn/add-react-to-an-existing-project#step-2-render-react-components-anywhere-on-the-page
Building your first component
- Component lets split the UI into independent, reusable and isolated pieces
- Components are like JavaScript functions (conceptually)
- Accept arbitrary inputs (called "props")
- Props are read-only (function can't change it's own props)
- Return React elements describing what should appear on the screen
- Accept arbitrary inputs (called "props")
- The simple one-page app example
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<script crossorigin>
// const process = { 'env': { 'NODE_ENV' : 'development' } };
</script>
<script crossorigin src="https://unpkg.com/react@18.3.1/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
</head>
<body>
<div id="rooty"></div>
<script type="text/babel">
ReactDOM.createRoot(
document.getElementById('rooty')
).render(<h1>Hi Universe!</h1>);
</script>
</body>
</html>
How components work in React
- Components implement a render() method
- Takes input data and returns what to display
- Often uses an XML-like syntax called JSX
- Can access input data passed into the component via this.props
- Input data passed into the component can be accessed by render() via this.props
Example 1
//// JSX code
class HelloMessage extends React.Component {
render() {
// JSX element treated as JavaScript expression:
// can be saved in a variable, passed to a function, stored in an object or array, etc
return <div>Hello {this.props.name}</div>;
}
}
ReactDOM.createRoot(document.getElementById('rooty')).render(<HelloMessage name="Robert" />);
//// COMPILED JS
// class HelloMessage extends React.Component {
// render() {
// return React.createElement(
// "div",
// null,
// "Hello ",
// this.props.name
// );
// }
// }
// ReactDOM.createRoot(document.getElementById('rooty')).render(React.createElement(HelloMessage, { name: "Robert" }));
Exercise 1
Rewrite it into React function (-:
The component life cycle
- In application with many components
- Components are destroyed
- Resources taken by the components have to be free up
- Mounting
- Whenever the component is rendered to the DOM for the first time
- Unmounting
- Whenever the DOM produced by the component is removed
- Special(our own) methods called lifecycle hooks
- setState() schedules updates to the component local state
- "Common lifecycles"
Handling state in React
- State is similar to props
- But it is private and fully controlled by the component
- Local state is a feature available only to classes
- Component
- Takes input data (accessed via this.props)
- Can maintain internal state data (accessed via this.state)
- When a component's state data changes, the rendered markup will be updated by re-invoking render()
Example 2
//// JSX part
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = {secondsElapsed: 0};
}
tick() {
this.setState((prevState) => ({
secondsElapsed: prevState.secondsElapsed + 1
}));
}
// Lifecycle hooks
componentDidMount() {
this.interval = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div>Seconds Elapsed: {this.state.secondsElapsed}</div>
);
}
}
//// 'createRoot()' replaced 'ReactDOM.render()', below previous way (for React 17 and older)
// ReactDOM.render(<Timer />, document.getElementById('rooty'));
ReactDOM.createRoot(document.getElementById('rooty')).render( <Timer /> );
//// COMPILED JS, rendering part only
// ( ... )
// render() {
// return React.createElement(
// "div",
// null,
// "Seconds Elapsed: ",
// this.state.secondsElapsed
// );
// }
// ( ... )
Exercise 2
Guess what? (-!
- Write function'ish version of it - of course!
Managing state
- React on its own does not provide built-in support for state management
- The React community uses libraries
- Redux
- MobX
- xstate
- React state vs. Redux state
Redux
- Relies on synchronizing data through a centralized and immutable store of data
- Updates to that data will trigger a re-render of the application
- State is updated in an immutable fashion
- Sending explicit action messages which must be handled by functions called reducers
- Because of the explicit nature, it is often easier to reason about how an action will affect the state of our program
MobX
- Relies on functional reactive patterns
- State is wrapped through observables and passed through as props
- Keeps state fully synchronized for observers
- Simply marks state as observable.
- Already written in TypeScript
xstate
- Relies on event-driven programming, state machines, statecharts, and the actor model
- manages application and workflow state (fe, be, or any js run time environment)
- models logic as actors and state machines
- API https://www.jsdocs.io/package/xstate
- Generator https://stately.ai/docs/generate-react
React state vs. Redux state
- Use React state for things that don’t matter globally
- The form is one-off
- The form’s data isn’t needed outside of it
- The form’s state is so complex, managing all of that with Redux would be even worse
- Use Redux for state that does matter globally
- We want the input value to outlive the component
- We have to have several instances of the form, synced
- We want to share particular input between different forms
- We want certain form state to have the impact on the rest of our app
Integrating React with other frameworks and plugins
- React is flexible
- Provides hooks that allow to interface with other libraries and frameworks
- For example we could use an external Markdown library and its remarkable class
- to convert the textarea's value in real time
- https://github.com/jonschlinkert/remarkable
- Or as an alternative - do the same by installing an existing component
Example 3, with ext plugin
// <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/remarkable/1.7.1/remarkable.js"></script>
//
// JSX code
class MarkdownEditor extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {value: 'Type some *markdown* here! # babe - meow'};
}
handleChange(e) {
this.setState({value: e.target.value});
}
getRawMarkup() {
var md = new Remarkable();
return { __html: md.render(this.state.value) };
}
render() {
return (
<div className="MarkdownEditor">
<h3>Input</h3>
<textarea
onChange={this.handleChange}
defaultValue={this.state.value} />
<h3>Output</h3>
<div
className="content"
dangerouslySetInnerHTML={this.getRawMarkup()}
/>
</div>
);
}
}
ReactDOM.createRoot(document.getElementById('rooty')).render(<MarkdownEditor />);
Exercise 3
- Yup, you know what to do now, for sure (-'
- You do, right? (-,
- Function, obviously!
- Oh well, let's "kill one stone with many birds", shall we?
- Create short training course materials: "How to kill one stone with many birds?"
- Keep it really simple as a presentation - just a couple of slides (2 or 3)
- Use this extension - https://github.com/rexxars/react-markdown
Bringing it all together - an application
- Using props and state usually is enough to create the whole application
- Below TODO list example
- uses state to track the current list of items
- Also tracks the text that the user has entered
- Event handlers appear to be rendered inline
- But they will be collected and implemented using event delegation
Example 4, app example
// JSX code
class TodoApp extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {items: [], text: ''};
}
render() {
return (
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input onChange={this.handleChange} value={this.state.text} />
<button>{'Add #' + (this.state.items.length + 1)}</button>
</form>
</div>
);
}
handleChange(e) {
this.setState({text: e.target.value});
}
handleSubmit(e) {
e.preventDefault();
var newItem = {
text: this.state.text,
id: Date.now()
};
this.setState((prevState) => ({
items: prevState.items.concat(newItem),
text: ''
}));
}
}
class TodoList extends React.Component {
render() {
return (
<ul>
{this.props.items.map(item => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
}
}
ReactDOM.createRoot(document.getElementById('rooty')).render(<TodoApp />);
Exercise 4
Yeah, again - I know (---;
- Make it hooked!
Setting up your development environment
- Create new app
- Add React to an existing app
Create new app
- FB incubator - the source is always the best, but.. it's deprecated now
- Common way also at the beginning is to use one of available starter-kits/fullStacks frameworks
- https://nextjs.org/ (mern.io is deprecated now)
- https://reactrouter.com/start/framework/installation
- Some additional helpers
Create new app Con't
- Later we can adjust it and move to production
- change the configuration
- provide security (handling users via login and passwd, etc)
- setup the db (mysql, mongodb, etc)
- wire our existing web services, write new
Add React to an Existing App
- No need to rewrite your app to start using React.
- Start with small part of application (small widget), and see if it works well for our use case
- React can be used without a build pipeline
- It's recommended to set it up to be more productive
- Build pipeline
- Package manager (Yarn, npm, etc)
- Vast ecosystem of third-party packages, easy to install or update them
- Bundler (webpack, Browserify, vite, parcel, rsbuild, etc).
- Lets to write modular code and bundle it together into small packages to optimize load time
- Compiler (Babel, etc)
- Lets to write modern JavaScript code that still works in older browsers
- Package manager (Yarn, npm, etc)
Exercise 5, Full envi, ts way
We will create simple application with 'vite' and 'nodejs'. We will do it in steps, to cover most important elements of 'Reactjs'. Each step will be explained separately. Envi preparation steps (command line, in linux you might gonna need also 'sudo ' before the 'npm') npm create vite@latest mya -- --template react-ts cd mya npm i npm run dev
How to use vite with nodejs goodies
# enabling app in dev envi
npm run dev
# builds the app for production to the `build` folder
npm run build
- Step 1
- Looking at the template code
- Step 2
- change the file src/App.tsx
import './App.css'; function App() { return ( <div className="App"> <p>Hi Universe!</p> </div> ); } export default App;
- change the file src/App.tsx
- Step 3 (tricky one!)
- Create new component here components/Text.tsx
const Text = () => { return ( <p className="text">Lorem ipsum</p> ); } export default Text;
- Create new component here components/Text.tsx
- Step 4
- Modify main component src/App.tsx
import './App.css'; import Text from './components/Text'; function App() { return ( <div className="App"> <p>Hi Universe!</p> <Text /> </div> ); } export default App;
- Modify main component src/App.tsx
- Step 5
- Understanding state. Change main component file again src/App.tsx
import './App.css'; import { React, useState } from 'react'; import Text from './components/Text'; function App() { const [text, setText] = useState('Not clicked!'); function onButtonClick() { setText('Clicked!'); } return ( <div className="App"> <p>Hi Universe!</p> <Text /> <p>{text}</p> <button onClick={onButtonClick}>Click</button> </div> ); } export default App;
- Understanding state. Change main component file again src/App.tsx
- Step 6 (couple of fix-me cases here!)
- Passing parameters(also state) to components.
- Step 6.1. Modify file src/components/Text.tsx
import PropTypes from 'prop-types'; const Text = (props) => { return ( <div> <p className="text">{props.staticText}</p> <p className="text"> {`Text from parent: ${props.clickText}`} </p> </div> ); } Text.propTypes = { staticText: PropTypes.string.isRequired, clickText: PropTypes.string.isRequired } export default Text;
- Step 6.2. Modify main component file src/App.tsx
import './App.css'; import { React, useState } from 'react'; import Text from './components/Text'; function App() { const [text, setText] = useState('Not clicked!'); function onButtonClick() { setText('Clicked!'); } return ( <div className="App"> <p>Hi Universe!</p> {/* <Text /> */} <Text // Comment out the line below and check the 'console' staticText="Text from child component" clickText={text} /> <p>{text}</p> <button onClick={onButtonClick}>Click</button> </div> ); } export default App;
- Step 6.1. Modify file src/components/Text.tsx
- Passing parameters(also state) to components.
Defining our components' parent/child relationships
- Containment
- Specialization
- https://react.dev/learn/understanding-your-ui-as-a-tree
- Legacy https://reactjs.org/docs/composition-vs-inheritance.html
Lifting state up
- A single "source of truth" for any data that changes
- The state is first added to the component that needs it for rendering
- Then, if other components also need it, we can lift it up to their closest common ancestor
- Don't try to sync the state between different components, rely on the top-down data flow
- More "boilerplate" code than in two-way binding approaches
- But it takes less work to find and isolate bugs
- any state "lives" in some component and that component alone can change it
- the surface area for bugs is greatly reduced
- We can also implement any custom logic to reject or transform user input
- But it takes less work to find and isolate bugs
- If something can be derived from either props or state, it probably shouldn’t be in the state
Containment
- To reuse code between components
- Composition model is recommended instead of inheritance
- For not known children AOT in generic components
- pass children elements directly with
{props.children}
- by nesting the JSX
- For multiple generic "barrels" in a component use our own convention
- pass our own React elements as props like any other data
- pass children elements directly with
Specialization
- Components as special cases of other components
- PublicCourseEvent and ConsultancyEvent are special cases of CourseEvent
- Use composition
- more "specific" component renders a more “generic” one
- and configures it with props
- To reuse non-UI functionality between components
- extract it into a separate JavaScript module
- the components may import it and use its constructs without extending it
Event handling and conditional rendering
- Event handling
- Conditional rendering
Container vs Presentational Components
"Remember, components don’t have to emit DOM. They only need to provide composition boundaries between UI concerns" Dan Abramov (Co-author of Redux and Create React App)
- Presentational and Container Components
- it is a distinction in their purpose, not a technical one
- https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
- use this approach only if it fits our business (processes, flow, etc)
- it can be also achieved with custom Hooks instead, so choose wisely - do not treat it as a golden hammer (-;
- Higher-Order Components
- rarely used in modern react code
- Legacy https://reactjs.org/docs/higher-order-components.html
Presentational Components
Dan Abramov's presentational components:
- Are concerned with how things look
- May contain both presentational and container components** inside, and usually have some DOM markup and styles of their own
- Often allow containment via this.props.children
- Have no dependencies on the rest of the app, such as Flux actions or stores
- Don’t specify how the data is loaded or mutated
- Receive data and callbacks exclusively via props
- Rarely have their own state (when they do, it’s UI state rather than data)
- Are written as functional components unless they need state, lifecycle hooks, or performance optimizations
- Examples: Page, Sidebar, Story, UserInfo, List
Container Components
Dan's container components:
- Are concerned with how things work
- May contain both presentational and container components inside
- but usually don’t have any DOM markup of their own except for some wrapping divs,
- and never have any styles
- Provide the data and behavior to presentational or other container components
- Call Flux actions and provide these as callbacks to the presentational components
- Are often stateful, as they tend to serve as data sources
- Are usually generated using higher order components
- such as connect() from React Redux, createContainer() from Relay, or Container.create() from Flux Utils,
- rather than written by hand
- Examples: UserPage, FollowersSidebar, StoryContainer, FollowedUserList
What are the benefits
- Better separation of concerns
- We understand our app and our UI better by writing components this way
- Better reusability
- We can use the same presentational component with completely different state sources
- and turn those into separate container components that can be further reused
- Presentational components are essentially our app’s palette
- We can put them on a single page and let the designer tweak all their variations without touching the app’s logic
- We can run screenshot regression tests on that page
- This forces us to extract layout components such as Sidebar, Page, ContextMenu and use this.props.children
- instead of duplicating the same markup and layout in several container components
Designing our React app
- Prepare dry dummy interface
- Break the UI into a Component Hierarchy
- Build a static version in React (just props, no state yet)
- Identify complete and minimal representation of UI state
- Identify where our state should Live
- Add inverse data Flow
Identify the minimal representation of UI state
Criteria for each piece of data (yes = probably not state)
- Passed in from a parent via props?
- Remain unchanged over time?
- Computable based on any other state or props in our component?
Identify where our state should Live
For each piece of state in our application
- Identify every component that renders something based on that state
- Find a common owner component
- a single component above all the components that need the state in the hierarchy
- Either the common owner or another component higher up in the hierarchy should own the state
- If we can’t find a component where it makes sense to own the state
- create a new component simply for holding the state
- and add it somewhere in the hierarchy above the common owner component
Main Exercises
- Pesel app
- Migrate from jQuery to React
- do it with React functions (-----:
- Separate validations into JS module
- Migrate from jQuery to React
- Jewel app
- First migrate it from Angular to React - yes, functioooooooons ruuuleeeeezzzzzz (--;
- follow the best practices - design first, then code it (check again this Approach)
- Improve it with form element
- Extend it with adding new jewel to model
- Add custom validation - adding same jewel not allowed
- Make sure gamers can see the list of available jewels
- Wrap it into simple navigation - use react-router module
- Home page - shows only description of the game
- Play it - redirects to the game itself
- Show jewels - view with all the gems
- Add Jewel - new jewel form
- Pesel - form from the previous exercise
- Simple - our first full example (clicked or not clicked)
- Make a view with single jewel
- Improve our jewel - add description field
- Allow to remove one jewel
- Extend it - removal of all jewels
- Make one jewel editable
- First migrate it from Angular to React - yes, functioooooooons ruuuleeeeezzzzzz (--;
Handling Forms in React, classes way
Collapsed by default, old-school way here only
Using context instead of props
- Passing props can become inconvenient if
- we need to pass through many components
- many components need the same info
- Context makes some information available
- to any component in the tree below the parent
- no matter how deep it is
- no need to explicitly passing through props
- The context itself does not hold the information
- it only represents the kind of information we can provide or read from components
- Related docs:
- Exercise
- Try to re-design our Ftj form with context
- What can you say?
- What could be in the custom context there and what not (or shouldn't)?
- Try to re-design our Ftj form with context
Routing in React
- Static Routing
- configuration happens before our app renders
- Dynamic Routing
- routing that takes place as our app is rendering
- Nested routes
- Responsive routes
- https://reactrouter.com/en/main
- Router framework
npx create-react-router@latest my-react-router-app
Adding Router lib
npm install react-router-dom
Dynamic routing
- Routers
- Route Matching
- Main Route Props
- Navigation
Routers
- A router component at the core
- Creates a specialized history object
- For web projects ('react-router-dom' lib)
- <BrowserRouter> - a server that responds to requests
- <HashRouter> - a static file server
- For mobiles ('react-router-native' lib)
- <NativeRouter>
Route Matching
- Comparing a <Route>'s path prop to the current location’s pathname
- When matches it will render its content, otherwise null
- A <Route> with no path will always match
- Route matching components
- <Route>
- include to render content based on the location
- list a number of possible <Route>s next to each other
- <Routes>
- used to group <Route>s together
- <Route>
Main Route Props
- element - should be used for an existing element/component
- React.Component, functional component, just element
- path - the url's part
- <Link> - component to create links
- <NavLink> - a special type of <Link>
- can style itself as "active" when its to prop matches the current location
- <Navigate> - to force navigation
Router example
import { Routes, Route, Link } from "react-router-dom";
const Home = () => (
<div>
<h2>Home</h2>
<p>Navigation example</p>
{/* <YourHomeComponent /> */}
</div>
);
const About = () => (
<div>
<h2>About</h2>
<p>What are we doing here?</p>
</div>
);
const MyApp = () => {
return (
<div>
<nav>
<li>
<Link to={"/"}>Home</Link>
</li>
<li>
<Link to={"/about"}>About</Link>
</li>
</nav>
<hr />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</div>
);
}
export default MyApp;
Nested Routes
- Router has no 'nesting' API
- Route is just a component (like div, etc)
Nested routes example
import { Routes, Route, Link, Outlet } from "react-router-dom";
import Timer from "./Timer";
function Home() {
return ( <div>HOME page</div> );
}
function Messages() {
return ( <div><p>Message 1</p><p>Message 2</p></div> );
}
function Todos() {
return (
<>
<div>
<h4>Todo 1</h4>
<p>Fix the car</p>
</div>
<div>
<h4>Todo 2</h4>
<p>Spend some time with wife</p>
</div>
</>
);
}
function Menu() {
return (
<div>
<h2>Menu</h2>
<nav>
<li><Link to={"messages"}>Messages</Link></li>
<li><Link to={"todos"}>Todos</Link></li>
</nav>
{/* This element will render either <Messages> when the URL is
"/messages" or <Todos> at "/todos"
*/}
<Outlet />
</div>
);
}
function Nested() {
return (
<div>
<h1>Main Menu</h1>
<nav>
<li><Link to={"/"}>Home</Link></li>
<li><Link to={"/sub"}>Sub</Link></li>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="sub" element={<Menu />}>
<Route path="messages" element={<Messages />} />
<Route path="todos" element={<Todos />} />
</Route>
</Routes>
</div>
);
}
export default Nested;
Router Exercises
- Replace todos component with our Todos from this Example
- Add another link on the parent level
- It should show our Timer Example
- Create 2nd level sub-menu
- It should start from Messages
- Put one link there only - showing some Contact details
Managing state with Redux
- State of our app is stored in an object tree inside a single store
- To change the state tree we emit an action, an object describing what happened
- To specify how the actions transform the state tree, we write reducers
- Doesn't support many stores
- instead of adding stores, we split the root reducer into smaller reducers
- independently operating on the different parts of the state tree
- https://redux.js.org/introduction
Examples and exercises
- reduxExamples_
- crud, jwt, hooks
- redux-toolkit-crud - fix me, again (-;
- Rewrite our dynamic form example with Redux
- Rewrite our FTJ app with Redux
Managing state with Mobx
- Mobx is not a container for the state (not like Redux)
- To make objects trackable for MobX
- Use the @observable decorator or observable(object or array) functions
- To create functions that can automatically derive their value from the state
- Use the @computed decorator
- To automatically run functions that depend on some observable state
- Use autorun
- useful for logging, making network requests, etc
- To make React components truly reactive
- Use the @observer decorator from the mobx-react package
- They will update automatically and efficiently (also in large complex applications with large amounts of data)
- https://mobx.js.org/
Example
// Define your state and make it observable
import {observable} from 'mobx';
var appState = observable({
timer: 0
});
// Create a view that responds to changes in the State
import {observer} from 'mobx-react';
@observer
class TimerView extends React.Component {
render() {
return (<button onClick={this.onReset.bind(this)}>
Seconds passed: {this.props.appState.timer}
</button>);
}
onReset () {
this.props.appState.resetTimer();
}
};
ReactDOM.render(<TimerView appState={appState} />, document.body);
// Modify the State
appState.resetTimer = action(function reset() {
appState.timer = 0;
});
setInterval(action(function tick() {
appState.timer += 1;
}), 1000);
Mobx Exercise
- Rewrite our dynamic form example with Mobx
- Use this boilerplate https://github.com/mobxjs/mobx-react-boilerplate
- TS version https://github.com/mobxjs/mobx-react-typescript-boilerplate
Hooks
- Let use: props, state, context, refs, lifecycle
- without writing a class
- provide new way to combine them
- Optional and backwards-compatible
- Work side-by-side with existing code - can be adopted gradually
- Functions that:
- let "hook into" React state and lifecycle features from function components
- don’t work inside classes
Hooks Con't
- Allow to reuse stateful logic without changing component hierarchy
- Let split one component into smaller functions based on what pieces are related
- Examples: setting up a subscription or fetching data
- Common: useState, useEffect, useContext, useRef
- Custom hooks - reusing stateful behavior between different components
- Rules about calls
- only at the top level (not in: loops, conditions, nested f)
- only from function components (not from regular js) or custom hooks
- Examples
Hooks Examples
- useState()
- useMemo()
- useId()
- useCallback()
- useEffect()
- useRef()
- useContext()
useState()
- lets to add a state variable to our component which returns an array with two values
- Current State
- Set Function
- we can pass on initial value as well like below:- 234 and 'Gulliver'
import { useState } from 'react';
function Invoice() {
const [invNo, setInvNo] = useState(234);
const [companyName, setCompanyName] = useState('Gulliver');
}
useMemo()
- lets to cache the result of a calculation between re-renders
- prevents the unnecessary renders in our React Application
import { useMemo } from 'react';
function InvoicesList({ invoices, tab }) {
const visibleInvoices = useMemo(
() => filterInvoices(invoices, tab),
[invoices, tab]
);
}
useId()
- for generating unique IDs that can be passed to accessibility attributes
- which let to specify that two tags are related to each other
- where we can use useId() generated ids instead of hardcoding them
import { useId } from 'react';
function PasswordField() {
const passwordClueId = useId();
return (
<>
<input type="password" aria-describedby={passwordClueId} />
<p id={passwordClueId}>
</>
)
}
useCallback()
- lets to cache a function definition between re-renders
- useCallback caches a 'function' and useMemo caches a 'value/result of a calculation'
import { useCallback } fom 'react';
export default function BookingPage({ bookingId, referrer, theme }) {
const handleSubmit = useCallback((leadDetails) => {
post('/booking/' + bookingId+ '/buy' {
referrer,
leadDetails,
});
}, [bookingId, referrer]);
(...)
useEffect()
- lets to perform side-effects in the component
- side effects basically is an action which connects the component to the outside world
(...)
useEffect(() => {
const connection = createConnection(serverCourseEventUrl, courseEventRoomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverCourseEventUrl, courseEventRoomId]);
(...)
useRef()
- lets to reference a value that's not needed for rendering
- similar to useState, the difference is it doesn't cause a re-render when the value changes
import { useRef } from 'react';
function RefreshDadesktopSandbox() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
(...)
}
useContext()
- lets to read and subscribe to context from our component
- just like a data store (Redux, Mobx, etc)
import { useContext } from 'react';
import { ThemeLeadContext} from './ThemeLeadContext.js';
function SkinForLead() {
const theme = useContext(ThemeLeadContext);
(...)
return (
<section className="np-lead-section">
<ThemeLeadContext value={leadType + 1}>
{children}
</ThemeLeadContext>
</section>
);
}
Custom Hook
We can define our own hooks to use state and other React features without writing a class
- As a function, it takes input and returns output
- name starts with use (useQuery, useMedia.., etc)
- returns a normal, non-jsx data (not like in functional component)
- can use other hooks such as useState, useReF.. and other custom hooks (-;
- some libraries also provide hooks - useForm (React Hook Form), useMediaQuery (MUI), useQuery (React Query), etc
Custom Hook Con't
Benefits:
- Completely separate logic from user interface
- Reusable in many different components with the same processing logic
- Therefore, the logic only needs to be fixed in one place if it changes
- Share logic between components
- Hide code with complex logic in a component, make the component easier to read
When to use:
- piece of code (logic) is reused in many places
- logic is too long and complicated
- we write custom react library (-:
- ... ? (your ideas, please!)
- Example - let's look at useNavigate() in react-router lib
- Example/Exercise - react-ts-api
React Query
- Most state management libraries (incl Redux)
- good for working with client state
- not for server state
- persists remotely in a location the client side cannot control
- can become outdated - we need to make asynchronous APIs for fetching and updating
- React Query - one of the best libraries for managing server state
- It helps to fetch, cache, synchronize and update data without touching any global state
React Query Con't
Helps:
- to remove complicated and misunderstood code and replace with several React Query logic
- easier to maintain and build new features without worrying about wiring up new server state data sources
- make our application feel faster and more responsive
- save bandwidth and increase memory performance
- Example/Exercise - reactq-axios-ts
React Hook Form
- Less code, more performant
- reduces the amount of code we need to write
- removes unnecessary re-renders
- Isolate re-renders
- ability to isolate component re-renders -> better performance on our page or app
- Subscriptions - better performance
- ability to subscribe to individual input and form State update without re-rendering the entire form
- Faster mounting (than Formik, ReduxForm, etc)
- More here https://react-hook-form.com/
- Example/Exercise - react-hook-form-ts
MUI
- MUI System - CSS utilities
- BaseUI - blank canvas
- MaterialUI - Google's Material Design
- JoyUI - MUI's own design
- MUI X - free + paid pro-options
- Store with paid goodies
- Good alternative - https://chakra-ui.com/
MUI System
- Set of utilities (Flexbox, Shadows, Typography, etc)
- for quickly applying styles to components from: BUI, MUI, JUI
- or to any third-party components
- Helps to build custom designs more efficiently
- and to rapidly lay out custom designs
- Set of flexible, generic wrapper components (Box, Container, Grid, Stack)
- can be quickly customized using the sx prop
- styles can be defined directly within the components themselves
- simplifies bulky and redundant definitions of styled-components
- ensures consistency in one-off styles too
- can be quickly customized using the sx prop
- CSS tricks - https://css-tricks.com/snippets/css/a-guide-to-flexbox/
BaseUI
- Library of "unstyled" React components (standalone) and low-level hooks
- Set of foundational "headless" components
- can be built with using any styling solution
- no need to override any default style engine or theme
- "skeletal" version of Material UI
MaterialUI
- Uses this under the bonnet - https://m2.material.io/
- Comprehensive and can be used in production out of the box
- comes packaged with default styles
- is optimized to work with
- Emotion (default CSS engine, in v6) - https://emotion.sh/docs/introduction
- or styled-components - https://styled-components.com/
- Templates - https://mui.com/material-ui/getting-started/templates/
- Customizing - https://mui.com/material-ui/customization/how-to-customize/
- Theming - https://mui.com/material-ui/customization/theming/
- Tools/Builders
- Theme Creator - https://zenoo.github.io/mui-theme-creator/
- Color Palette Generator - https://m2.material.io/inline-tools/color/
- Customizing - https://mui.com/material-ui/customization/how-to-customize/
- Example - material-ui-vite-ts
MaterialUI Exercise
- Here choose the environment
- Next decide about the template (or not)
- https://mui.com/material-ui/getting-started/templates/
- let's take this one - Blog
- Finally try to use this builder
- https://zenoo.github.io/mui-theme-creator/
- create custom theme settings with it - apply them
- https://zenoo.github.io/mui-theme-creator/
JoyUI
- List Example - https://mui.com/joy-ui/react-list/
- Template Example - https://mui.com/joy-ui/getting-started/templates/order-dashboard/
React with Typescript
- Typescript basics
- From react docs
- From ts docs
- Best practices, use-cases, etc
- Examples
- fe_/react-ts..
- Exercises
- Create new app with ts included
npx create-react-app my-app-ts --template typescript
- Rewrite our PESEL app with TS
- Rewrite our FTJ
- Create new app with ts included
React Native
- Creates native apps for Android, iOS
- Written in JavaScript — rendered with native code
- Seamless Cross-Platform
- React components wrap existing native code
- interact with native APIs via React’s declarative UI paradigm and JavaScript
- Setup and Using
- Expo Go - quick and easy, but restricted SDK libs
- Native CLI - longer to prepare, but gives access to many external libs
- Related docs, examples
React Native Con't
npx create-expo-app nativeExample cd nativeExample npx expo start
Later on
- connect on the same Wifi with phone
- install Expo Go app on phone
- scan the QR
Full stack with React
- Examples
- https://nextjs.org/ (mern.io deprecated..)
- Installing - https://nextjs.org/docs/app/getting-started/installation
- Exercises
- Migrate ftj+pesel into nextjs
npx create-next-app@latest ftjrn cd ftjrn npm run dev
Server side rendering and SEO
- Next.js
- Server-rendered by default
- Automatic code splitting for faster page loads
- Simple client-side routing (page based)
- Webpack-based dev environment which supports Hot Module Replacement (HMR)
- Able to implement with Express or any other Node.js HTTP server
- Customizable with our own Babel and Webpack configurations
- Out-of-the-box tools for setting HTML tags for SEO
- https://nextjs.org/learn/
- https://zeit.co/blog/next
- react-seo npm package
- react-examples
- 14-Server-Rendering
- quickfix: remove internal from package.json npm run ssr-... scripts
Why not angular?
- Why not anyVeryPopularJavaScriptFramework.js instead?
- TypeScript
- Runtime Performance
- HTML & CSS
- Scale
- Native Rendering
- Size
- Flexibility
- Learning Curve
- https://vuejs.org/v2/guide/comparison.html#React
Debugging
- Devtools
- Error Boundaries
Upgrading, Refactoring
React's Lego
- React Components & Libraries
- Forms validation with hooks
- Easier handling of forms
Testing your React web application
- Jest
- jasmine
- karma-mocha
Jest Intro
- No config
- Supports - Babel, TypeScript, Node, React, Angular, Vue, etc
- "Snapshotting"
- Isolated
- Good API
Overview of Jest
- Zippy, secure
- tests have unique global state
- reliably runs tests in parallel
- runs previously failed tests first
- re-organizes runs based on how long test files take
Overview Con't
- Code coverage (--coverage)
- No setup needed, collects from entire projects (incl untested files)
- Simple mocking
- custom resolver for imports, mocks any object outside of scope
- rich Mock Functions API with readable syntax
Overview
- Whacking exceptions
- rich context for test-fail: toStrictEqual, toHaveProperty, toMatchSnapshoot, toThrowError, etc
- Well-documented
- maintained by Christopher Pojer from Facebook and contributors within the community
- Requires little configuration
- Extendable
Benefits of testing
Why and how
- Interfaces depend on browsers, user interactions, and many other variables
- implementing an effective testing strategy is difficult
- Consistent results are often affected by false negatives due to different factors (i.e. network)
- Frequent updates in UI: improve the experience, maximize conversions, new features
- Tests are hard to write and maintain ==> developers are less prone to cover their applications
- Tests make developers more confident ==> speed and quality
- Well tested code and well written tests ==> it works and is ready to ship
- Easier to refactor the code ==> functionalities do not change during the rewrite
- Running tests using Node.js and the console ==> faster, more predictable
Benefits of testing Con't
- Is new feature affecting other parts of the application
- Tests avoid regressions ==> tell if the new code breaks the old tests
- Greater confidence in writing new features ==> faster releases
- Code base more solid ==> new bugs can be reproduced, fixed, and covered by tests
- Testing components is easy - well organised and assigned responsibilities and boundaries
- Well written components (pure, composable, reusable) ==> can be tested as simple functions
- Main goals to test
- given different sets of props, components output is always correct
- covering all the various states that a component can have
- clicking a button ==> tests to check all the related event handlers
Benefits of testing Con't - tdd, design
- Tests can verify the component's behavior on edge cases
- all the props are null, or there is an error
- With React we can mount a tree of components and test the integration between them
- Techniques - test-driven development (TDD)
- Applying TDD ==> writing the tests first and then writing the code to pass the tests
- Force to think more about the design before implementing ==> usually leads to higher quality
Setting up the Testing Environment
- Examples
- Folder "testing"
- Tests from "react-training"
- Enzyme - helps to test Components' output
- manipulate, traverse, and in some ways simulate (like with jQuery)
- Cypress - e2e framework
Installing and Configuring Jest
- Initial setup
## Installing
npm install --save-dev jest
## Config
jest --init
## The rest depends on other tools: babel, webpack, typescript, etc
- More here:
- jestjs.io/docs/getting-started#additional-configuration
Running Watch Mode to Test File Changes
live-server --cors #manual tests with real browser
jest -o #runs only with uncommited changes (git, mercurial)
jest --watch #runs jest -o by default
jest --watchAll #runs all tests
### Interactively - Watch Usage: Press w to show more.
## Watch Usage
# › Press f to run only failed tests.
# › Press o to only run tests related to changed files.
# › Press q to quit watch mode.
# › Press p to filter by a filename regex pattern.
# › Press t to filter by a test name regex pattern.
# › Press Enter to trigger a test run.
More here: jestjs.io/docs/cli
Running Browser Tests through Node
npm test #via 'create-react-app' it uses by default the extension called 'react-scripts'
Testing a Sample JavaScript Application
TDD - Test Driven Development
- Red-Green-Refactor cycle
- Triangulation
- The more specific tests get, the more general production code needs to get
- Always implement the simplest thing that will possibly work
- Hard-coding when it's possible and to get to the real implementation - add more tests
- AAA rule: Arrange(Assemble), Act, Assert
- Design principles
- DRY - Don't Repeat Yourself
- Drying up tests when refactoring
- YAGNI - You Ain't Gonna Need It
- Hold off adding anything to project until we're really sure that it's necessary (adding a user story, a customer asks for it, etc)
- For example create-react-app application template - favicon.ico, a sample logo, CSS files, etc
- DRY - Don't Repeat Yourself
TDD Con't
Good vs Great
Good test | Great test |
---|---|
Arrange: Sets up test dependencies | Short |
Act: Executes production code under test | Descriptive |
Assert: Checks expectations are met | Independent of other tests |
lol | Has no side-effects |
Examples
- Example 1 - "1oneDetailOnly"
- Example 2 - "2viewsListAndDetail"
Design upfront
Exercises
- ("ex1") Display in the UI the rest of fields from model
- Wrap data into HTML table
- Add a heading to Appointment to make it clear which appointment time is being viewed
- Prepare fake data generator (DRY)
- Prepare new Find The Jewel project (name it ftj)
- Use create-react-app ( cd ; cd Documents/reactjsMaterials ; npx create-react-app ftj )
- Make oneJewel component and test it
- Make listJewels component and test it
- Clicked jewel button should be different then the rest of jewel buttons (add css class dynamically)
Testing a React App
- Simple form and user input
- Testing React Components
- About Stateful Components
Set up, execute function, assert results
Example
- "4simpleForm"
Exercises
- Add dropdown - choosing stylist (before time slot), filtering based on required service
- reflect stylists availability and the choice (update the table)
- Make form for adding new jewel and test it
- Refactor the app into JewelGame class component with state
- Use this ToDo list example as a skeleton
- Refactor the app into JewelGame class component with state
Testing the Business Logic
Test Doubles
- Used to verify interactions with collaborating objects
- Spies and stubs
- Extracting helper code into modules (readability - shorter and clearer)
Examples
- "6testDoubles"
Exercises
- Extend 6testDoubles
- Add a test to CustomerForm - the error state is cleared when the form is submitted again
- Update the AppointmentForm tests to use jest.fn(), jest.spyOn(), and all of the helpers
- Extend AppointmentForm so that it submits an appointment using a POST request to /appointments (endpoint returns a 201 Created status without any body)
- Update the tests in AppointmentsDayView to use the helpers
- Add engine component in ftj app
- Test it with doubles
- In ftj app refactor 'adding new jewel' into another component
Testing the User Interface
- Loader and render, shallow rendering
- Forms
- Filtering and Searching Data
- Testing Router
- Testing Redux
- Testing GraphQL
Loader and render, shallow rendering
- Stubbing out components
- Loader components correctly instantiate rendering components.
- Shallow rendering
- Stubbing and spying on child components - avoids running their side effects (fetch requests, etc)
- Easily assert that we set their props correctly
- Examples - "8forms"
Forms
- Client-side validation
- Handling server errors
- Indicating submit
- Examples - "8forms"
- Exercises
- Within "8forms"
- Clear any validation errors when corrected
- Use the 'onChange' handler instead of 'onBlur' (faster interaction with user)
- Disables the Submit button after submitting
- Write tests all functions within the formValidation module
- Simplify 'handleSubmit' - extract doSave func (pulls out the main body of the if statement)
- With ftj
- Validate adding new jewel, not allow when it exists already
Filtering and Searching Data
- More complex user interactions (between UI and an API)
- Order of adding features
- Tests help admit when we're doing the wrong thing
- Examples - "10searchingPaging"
- Exercises
- With "10searchingPaging"
- Disable the 'Previous' button if the user is on the first page
- Disable the 'Next' button if the current listing has fewer than 10 records on display
- The /customers endpoint supports a limit parameter - specifies the number of records that are returned
- Provide a mechanism for the user to change the number of records returned on each page
- For ftj
- Allow to search for jewels
Testing Router
- General rules for testing React Router
- Building a root component
- Using the location query string to store component state
- Examples - "12router"
- Exercises
- For ftj
- Make router for showing list of jewels and a single jewel
Testing Redux
- Testing a Redux saga
- Asynchronous requests with saga
- Switching out component state for Redux state
- Shifting workflow to Redux
- Examples - "13redux"
- Exercises
- For todo_ts
- Add button "RemoveAll"
Testing GraphQL
- Testing the Relay environment
- Building the GraphQL reducer
- Examples - "14graphql"
- Exercises
- With "14graphql"
- Reshape the remaining fetch calls to use their GraphQL counterparts
Running Snapshot Tests
Snapshot Tests
- Useful especially when testing presentational components
- They do not manage state
- Typically used to display data passed down from parent components as props
- or to display hardcoded data directly in the component itself
- Provided by Jest
- We simply want to make sure the HTML output of a component does not change unexpectedly
- Case scenario - developer does change the component's HTML structure
- He adds another paragraph element with static text
- Snapshot test will fail and provide a visual of the changes
- Example - "rtlExamples", 2
- Exercise - in ftj make a snapshot test
- Separate game description into new presentational component
Troubleshooting
- jest-dom methods
- allow to write more descriptive test code
- provide better context-specific error messages
- Using RTL (React Testing Library)
- Approach
- render React elements into the Document Object Model (DOM)
- select resulting DOM elements
- make assertions on the expected resulting behavior
- Examples - "rtlExamples"
- Approach
RTL examples
- 1 - test-utils VS enzyme VS rtl
- 2 - presentational, debug
- 3 - user events, interacting with APIs, again TDD
- 4 - integration testing, 3rd party plugins
- 5 - updating dependencies, enzyme2rtl, test-utils2rtl, best practices
- 6 - tools and plugins, more best practices
- 7 - e2e, cypress, cucumber
Photos Sources
- kurierhistoryczny.pl/uploads/articles/237/stanczykmaly_rf89RS.jpg
- cdn.shopify.com/s/files/1/0882/5118/products/Batman-The-Killing-Joke-Deluxe-Graphic-Novel-1008696_1024x1024.jpeg?v=1461690370
- wpblog.semaphoreci.com/wp-content/uploads/2019/01/Snapshot_Testing_React_Components_with_Jest_-_Semaphore_CI-1024x575.png