React
Contents of this page:
- GitHub Repos
- Docs and Blog Posts
- Automatically responding to code changes with Live Server
- Reagent
- create-react-app
- JSX and Babel
- React Developer Tools
- React forms
- Hooks and functional components
- Class components
- Routing - react-router-dom
- Fragments
- Controlled components
- React Routes
- Relationship between React and Node
GitHub Repos
Sadly by necessity some of my repos are private. Those that are private are clearly marked. For those that are, please don’t ask me to share the code, because I can’t. They’re listed here purely for my reference.
- getting-started-with-tdd-in-react
- MenopauseTracker-javascript
- react-big-calendar
- I found this on my hard disk after I cloned it from elsewhere. When I tried to create a new repo for it I just got a ton of security warnings because all the dependencies were out of date, so I got rid of my copy. This version is the source version, at intljusticemission.
- It was used by another project - MenopauseTracker, I think.
- Samba (PRIVATE)
- See sub-folders son, sig and vis**
- CBF PRIVATE (Accessible to Clare only):
- cbf/react-starter-files
- cbf/cbf-sample-solutions/software engineering/C_react/2022-10-sample-solutions
- cbf/react-starter-files-solutions
- [Directory of all sample CBF React code](https://github.com/claresudbery/cbf-sample-solutions/blob/main/README.md#react]
Docs and Blog Posts
- ReactiveX
- Difference between a framework and a library (spoiler: it’s all about inversion of control)
Automatically responding to code changes with Live Server
- On command line:
npm install -g live-server
- Then:
live-server
- This will automatically launch the default browser. When you make a change to any file, the browser will reload the page - unless it was a CSS file in which case the changes are applied without a reload.
- More here
Reagent
- Reagent is a library – a Clojurescript wrapper around react js. See Clojure notes
create-react-app
create-react-app - Intro
- As recommended here
- Create React App is an officially supported way to create single-page React applications. It offers a modern build setup with no configuration.
- create-react-app - getting-started
- My sample repo
How to start an app created using create-react-app
- On command line:
npm start
(don’t forgetnpm install
first) - If you want to use a different port:
- You can just run
npm start
and if someting is already on port 3000, it will detect this and give you the option to use a different port (it will automatically choose an alternative port for you) - Or you can place a file called
.env
in the root alongsidepackage.json
and add the linePORT=4200
(for example) - Or you can edit the
start
script line inpackage.json
, to look like this:"start": "set PORT=3006 && react-scripts start"
- You can just run
create-react-app - Troubleshooting getting started
Troubleshooting node version
- I had node v 13 which didn’t work (
The engine "node" is incompatible with this module. Expected version "^10 or ^12 or >=14". Got "13.10.1"
) so I upgraded node- On Windows, I just used the Windows installer but it took a bit of doing to get it right on both Windows and my Mac.
- See troubleshooting notes on my node page.
Troubleshooting getting started with a project not created on your machine
- If you’re getting errors about
create-script
not existing, this probably means you don’t have anode_modules
folder yet. - This means you haven’t installed your packages yet.
- If your project is using
yarn
(there’ll be ayarn.lock
file in the root folder), you need to run theyarn
command. - If your project is using
npm
(there won’t be ayarn.lock
file in the root folder, but there will bepackages-lock.json
), you need to run thenpm install
command.
Troubleshooting yarn vs npm
- I was experimenting with developing the same project on two different machines (a Windows machine and a Macbook, as it happens, but that wasn’t actually relevant to this problem) and I came up against a conflict between
npm
andyarn
.- On my macbook I had
yarn
installed. This was apparently detected bycreate-react-app
and the project was built to work withyarn
. When I pulled the code onto my Windows machine - where I didn’t haveyarn
installed - I couldn’t run the code becauseyarn start
didn’t work (it was configured to run usingnpm start
instead). - The solution was to install
yarn
on my Windows machine (where I was running the project in GitBash) usingnpm install -g yarn
, and then migrate the project fromnpm
toyarn
. Full instructions here.- You can see the resulting commit here.
- See package management notes on my node page for further info on yarn and npm.
- On my macbook I had
create-react-app - Scratchpad
create-react-app-playground
npx create-react-app create-react-app-playground --template typescript
JSX and Babel
- Stands for JavaScript eXtensible markup language. So a bit like XML.
- Allows you to write lines of code like this:
const element = <h1>Hello, world!</h1>;
- Lines like the above are transpiled into Javascript
React.createElement()
calls via theBabeljs.io
library - You can use the Babel repl to test the compiler in the browser.
- You can embed JavaScript in JSX using
{}
like this:const element = <h1>{name}'s React Page</h1>;
React Developer Tools
- Chrome extension, v useful. Can be found here.
React forms
- useful demo here
- Passing data and events between React components
- (Clare only) Example forms here, in the jsx-components/bonus-greeting folder. There are four different versions. You can switch between them by changing which component is referenced in
src/App.js
.
Hooks and functional components
useState hook
useState
is the method used to change state in functional components- Typically it looks like this:
const [count, setCount] = useState(0);
- This example uses array destructuring to set the variable
count
with a default of 0 and a method ofsetCount
for updating the variable.
- This example uses array destructuring to set the variable
- This code contains an example
useEffect hook
- The
useEffect()
hook tells your component to do something after every render.
useEffect(() => {
document.title = `${count} Clicks Counted`
});
- The code in
useEffect
above would be called every time a component is rendered. - This would means that the
title
tag of the site will change on each render if the variablecount
has changed useEffect
is equivalent to the class component methods ofcomponentDidMount()
,componentDidUpdate()
andcomponentWillUnMount()
all in oneuseEffect()
takes two arguments. The first is the function to call, and the second argument is an array which can be used to define how many times the first argument should be called
Class components
Lifecycle
- Lifecycle Methods (in order of execution):
- Mounting (Birth)
- constuctor()
- static getDerivedStateFromProps()
- render()
- componentDidMount()
- Updating (Growth)
- static getDerivedStateFromProps()
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
- Unmounting (Death)
- componentWillUnmount()
- Mounting (Birth)
- Special methods allow you to call code that can help setup or clear up resources when a component mounts or unmounts.
- The order of execution of the components are important for when they are called.
- Lifecycle cheatsheet
State
- React has another special built-in object called
state
, which allows components to create and manage their own data - Unlike
props
, components cannot pass data withstate
, but they can create and manage it internally- Components can receive data via
props
and then store it in their own internalstate
via the constructor - If you want to set state using props, pass props as the second argument of the
setState()
method e.g.this.setState((state,props) => ({lastname: props.lastname}));
- Components can receive data via
state
is set in the constructor of a component which is called only once when the component is created:this.state = { firstname: "Donna", lastname: "Summer" }
state
should not be modified directly but can be modified with a special method calledsetState()
:this.setState({lastname: "Winter"});
- Changing the state of a React component will trigger a re-rendering of the component (not the whole DOM)
- It’s important to note that changing state directly is possible, but bad practice
- Changing state directly will not cause the component to re-render, so, don’t do this when you want to update state:
this.state.lastname = "Winter";
- With React Hooks, state can be changed in functional and class components
- Without React Hooks, state can only be used in class components
useState
is the method used to change state in functional- This form code (available to Clare only) contains an example
Routing - react-router-dom
- Can use popular standard routing library
react-router-dom
npm install react-router-dom
- Types of router:
- HashRouter
- Uses hash portion of url (the window.location.hash) to keep UI in sync with url
- eg
<a href="#/bookcase/first">
- MemoryRouter
- keeps history of url in memory - doesn’t read or write to address bar
- BrowserRouter
- Uses the HTML5 history API (
pushState
,replaceState
and thepopstate
event) to keep your UI in sync with the URL - Example here in bookcase app (available to Clare only)
- Uses the HTML5 history API (
- HashRouter
- The
Link
element:- The component is used to navigate to the different parts of an application by way of hyperlinks.
- It’s similar to HTML’s anchor element (
<a href="/">link</a>
) but the main difference is that using the Link component does not reload the page, it renders the elements based on the matching Router - Link syntax:
<Link to="/items">Items</Link>
Fragments
- By default, React components can only return one base DOM element
- This will throw a syntax error:
render(){
return(
<div>First</div>
<div>Second</div>
);
}
- Until I discovered fragments I got round this by adding unnecessary parent
div
elements to wrap everything - Fragment provides a base element that can be used to group a list of children without adding extra nodes to the DOM, reducing bloat
- Like this:
render(){
return(
<React.Fragment>
<div>First</div>
<div>Second</div>
</React.Fragment>
);
}
- Fragments declared with the explicit
<React.Fragment>
syntax may have keys. Key is the only attribute that can be passed to a Fragment - Keys are required when a child element in a list requires unique “keys”. Without the key attribute React will raise a key warning.
- The new short syntax will allow you to use what looks like empty tags <></> instead of
<React.Fragment>
- No attributes can be passed using the short syntax
- Like this:
render(){
return(
<>
<div>First</div>
<div>Second</div>
</>
);
}
Controlled components
- These are how React handles HTML forms
- They allow you to use React state to track values being typed into form elements
- Here is an example from the
bonus-greeting
app in here (available to Clare only):- The
final_name
is not a requirement for this approach, it just allowed me to have a separate value for when the user hit Submit, that wouldn’t bep opulated until they’d finished typing. - The controlled component in the example below is the name component. The code has been expanded for readability but basically this snippet is the controlled component:
<label>Enter your name: <input type="text" value={name} onChange={(e) => setName(e.target.value)}/></label>
- The
function GreetingForm1() {
const [name, setName] = useState("");
const [final_name, setFinalName] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
setFinalName(name);
}
return (
<div>
<form onSubmit={handleSubmit}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<input type="submit" />
</form>
<Greeting name={final_name} bio={final_bio} />
</div>
);
}
React Routes
React Routes - Adding code to all pages
- If you’re going to include routes, your top level element returned by the
App
component has to be aRouter
- As long as you include a
"/"
route, whatever lives in that element will be what’s displayed to the user when they first arrive at the site. - If you want to add other things that get displayed by default, you can return them from the
App
component, but they have to go inside theRouter
element. - This will work:
export default function App() {
return (
<Router>
<ul className="breadcrumb">
<li><Link to="/"> All Pets </Link></li>
</ul>
<Routes>
<Route path="/" element={<Home/>} />
</Routes>
</Router>
);
- This won’t work:
export default function App() {
return (
<>
<ul className="breadcrumb">
<li><Link to="/"> All Pets </Link></li>
</ul>
<Router>
<Routes>
<Route path="/" element={<Home/>} />
</Routes>
</Router>
</>
);
React Routes - components vs elements
- Some of the sample code you’ll see for routes uses
component
and some of it useselement
element={}
is version 6 syntax and preferred overcomponent={}
Component example (also see here):
<Router>
<Route exact path="/" component={displayItems} />
</Router>
Element example (also see here and here):
<Router>
<Routes>
<Route path="/" element={<Home/>} />
</Routes>
</Router>
element={}
is version 6 syntax and preferred overcomponent={}
- Explanation: “Using elements instead of components means we don’t have to provide a passProps-style API so you can get the props you need to your elements. For example, in a component-based API there is no good way to pass props to the
<Profile>
element that is rendered when<Route path=":userId" component={Profile} />
matches.”- (Copied from here)
Relationship between React and Node
- I’m a little bit unclear, but I think it’s like this:
- Node is used to run a server which you can use to run React locally
- webpack is used to bundle your React js, and webpack is a node package.
- I think maybe it’s technically possible to write React apps without using node?
- create-react-app is a Node package and relies on Node.