From the ground up: Import, ReactDOM, JSX, Components, Styling, Props, Data, State, and Hooks.
Once react
and react-dom
are connected as dependencies, we can import React to our component.
import React from "react"
React isn't just for front-end web development; we can also build native apps (with React Native). So to be able to render our app to the browser, we need to use ReactDOM
.
First, import ReactDOM
to the main component, usually index.js
. Normally, ReactDOM
only has to be imported to index.js
, because everything else is rendered within it.
import React from "react"
import ReactDOM from "react-dom"
ReactDOM
's render
method takes in two parameters:
ReactDOM.render(whatToRender, whereToRender)
document.getElementById("root")
is a good one, if you have an HTML with a <div id="root"></div>
.ReactDOM.render(<App />, document.getElementById("root"))
JSX allows us to ~basically~ write HTML in JavaScript. JSX is included in React, when we import React from "react"
.
Only one element can be rendered. To render more than one element, they must be wrapped in a container (<div><More /><Content /></div>
)
To add JavaScript inside JSX, just wrap the JavaScript code in curly braces {variable}
.
const firstName = "Cécile"
const firstName = "Cécile"
const App = () => <h3>My name is firstName + " " lastName</h3> // will literally render 'My name is firstName + " " lastName'
const App = () => <h3>My name is {firstName + " " lastName} // will render 'My name is Cécile Lebleu'
const App = () => <h3>My name is {`${firstName} ${lastName}`} // will render 'My name is Cécile Lebleu'
Components can be arrow functions...
const MyApp = () => <div>Content</div>
Or classic functions.
function App() {
return(
<div>
Content
</div>
)
}
These are all functional components. There's also class-based components, but I'll skip it because it's not actually necessary to know.
Components should be each in their own file.
In each component file, we need to import React, and export the component.
import React from "react"
const MyComponent = () => <div>My component</div>
export default MyComponent
Then, in our parent container (index.js
or other) we must import that component
import React from "react"
import ReactDOM from "react-dom"
import MyComponent from "./components/MyComponent"
ReactDOM.render(<MyComponent />, document.getElementById("root"))
function App() {
const components = myData.map(item =>
<Component
key={item.id}
parameter1={item.parameter1}
parameter2={item.parameter2}
/>
)
return (
<div>
{components}
</div>
)
}
If we're using an HTML and ReactDOM, we can import a classic CSS file into index.html
and style everything the old-fashioned way with CSS classes.
className
and not "class".const App = () => <h1 style={{
color: "blue",
backgroundColor: "aliceblue",
padding: 30, // auto: pixels
fontSize: "2rem"
}}>My App</h1>
const styles = {
color: "blue",
backgroundColor: "aliceblue",
padding: 30, // auto: pixels
fontSize: "2rem"
}
const App = () => <h1 style={styles}>My App</h1>
Props allow us to pass data down into components; similarly to image source links, a href links, different names or content in general.
Props are immutable — meaning, they can't be changed upwards through the React tree.
const Component = () => <div>
<p>{props.name}</p>
<img src={props.imageSrc} />
<a href={props.url}>{props.link}</a>
</div>
const App = (props) => <div>
<Component
name="Some Name"
imageSrc="http://placekitten.com/400/200"
url="www.some-site.com"
link="Some link"
/>
</div>
To use props in class-based components, you must use {this.props.name}
instead of {props.name}
.
There's a few sources of data we can use. Most often that will be from an HTTP call to an API, but we can also get data from a file.
const myData = [
{
id: 1,
content: "data content one"
},
{
id: 2,
content: "data content two"
}
]
export default myData
import React from "react"
import myData from "./myData"
The best way to use State is using the useState()
hook.
useState
has to be imported from React, luckily in one import statement.
import React, { useState } from "react"
This is a function that uses state:
function App() {
const state = useState("Yes")
return (
<p>Q: Should I learn state?<br />A: {state[0]}</p>
)
}
useState
returns an array. That's why in the example above we used {state[0]}
. But state isn't generally intended to be used that way, instead using array destructuring. Another way of writing the same example:
function App() {
const [state] = useState("Yes")
return (
<p>Q: Should I learn state?<br />A: {state}</p>
)
}
The second argument of useState
is a function that allows us to change the state directly (without having to use the o-ho-hol' setState
). The function can be defined outside the return
statement:
function App() {
const [count, setCount] = useState(0)
function increment() {
setCount(prevCount => prevCount + 1)
}
return (
<div>
<h1>{count}</h1>
<button onClick={increment}>Add</button>
</div>
)
}
Or directly in the event handler:
function App() {
const [count, setCount] = useState(0)
return (
<div>
<h1>{count}</h1>
<button
onClick={() => setCount(prevCount => prevCount + 1)}
>Add</button>
</div>
)
}
useEffect
is a hook that allows to add "side effects" to our code. Similar to useState
, useEffect
is a hook that comes with React. It's basically a replacement for the older lifecycle methods, like componentDidMount
and the like. Just like useState
, it has to be imported.
import React, { useEffect } from "react"
import React, {useState, useEffect} from "react"
import randomcolor from "randomcolor"
function App() {
const [count, setCount] = useState(0)
const [color, setColor] = useState("")
function increment() {
setCount(prevCount => prevCount + 1)
}
function decrement() {
setCount(prevCount => prevCount - 1)
}
useEffect(() => {
setColor(randomcolor())
}, [count])
return (
<div>
<h1 style={{color: color}}>{count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
)
}
useEffect
runs right after the state of count
changes, each time providing a new random color for the counter itself. Notice we pass an array with count
as the second argument: This tells useEffect
to run only when the state of count
is updated (but no other state). This effectively avoids infinite loops and pesky bugs.
To make it run only once — when the component first renders, but then never again — we can pass an empty array instead; basically saying "listen for the change of state in nothing".
useEffect(() => {
setColor(randomcolor())
}, [])