- Run this command
npm create vite@latest-
Name your project.
-
Select a framework: React.
-
Select a variant: JavaScript + React compiler.
-
Which linter: ESLint is prefered for small projects.
-
Run this command to initiate the server:
npm run devNormal pure DOM manipulation requires so much code and hard to read, So JSX is the solution as it allows to writenested HTML tags, but it is not HTML, React converts this JSX into JavaScript and updates the DOM.
As we mentioned, JSX is not HTML and has rules that makes it even more powerful
You can't return multiple elements sitting side by side as they need to wrapped in one parent container.
- This rule comes from JS rule which is you can't return 2 objects from the same function unless you wrap them in an array
- If you don't like to wrap them in a normal HTML tag, there is a component that React offers which is
React.Fragmentand can be shortened into<>.
- You can close tags like
<br>by adding/before>like<br />.
- HTML attributes sometimes conflict with JS reserved keywords like
for. for===>htmlFor.class===>className.- When this conflict happens, React suggests the correct attribute name in the dev console.
export const Welcome = () => {
const name = Ahmed Mahmoud;
const age = 21;
return (
<>
<h1>Welcome, {name}</h1>
<p>You are born in {new Date().getFullYear() - age}</p>
</>
)
}props in JSX are like arguements in JS.
- In
app.jsx
function App() {
return (
<>
<Welcome name="Ahmed" />
</>
)
}- In
Welcome.jsx
export const Welcome = (props) => {
return (
<h1>Welcome {props.name}!</h1>
)
}- You can destruct the props object.
- Strings are passed to the component in double quotes, everything else is in curly braces.
- You can use default props, it will be used when the passing values is missing or
undefined. - If you pass
nullor 0, it will not be used.
export const Greeting = ({ name = "Ahmed", message = "Hello" }) => {
return (
<h1>{message}, {name}!</h1>
)
}And that is how JS default params work, this ensures the point of JSX converted at the end to JS.
- Instead of destructing the props and passing it individually to the component we can do this:
import { Greeting } from './Greeting'
export const UserProfile = ({ id, ...rest }) => {
return (
<>
<Greeting {...rest} />
<p>Displaying profile for user {id}...</p>
</>
)
}- As HTML, we can nest components inside each other.
In ProfileWrapper.jsx
export const ProfileWrapper = ({ title, childeren }) => {
return (
<>
<div>
<h1>{title}</h1>
{children}
</div>
</>
)
}In App.jsx
import { UserProfile } from './UserProfile'
import { ProfileWrapper } from './ProfileWrapper'
function App () {
return (
<ProfileWrapper title="Facebook">
<UserProfile {...info} />
<button>Post</button>
</ProfileWrapper>
)
}
export default App- If statement: The simplest way, but usually causes a lot of duplication.
- Ternary operator: Allows to conditionally render parts of the component.
- AND operator: All or nothing.
<h3>{name} { isPremium && <span> $</span>}</h3>- Variables: you can prepare the JSX in variables to avoid messy components.
If you have a list of items like comments on a post and want to render them, it is not practical to write a div for each comment.
We can instead use map() function to map each comment to it's code.
const productElements = products.map((product) => {
return (
<div>
<h3>{product.name}</h3>
<p>Price: ${product.price}</p>
</div>
)
})Yocan even filter them according to a specific condition by filter(), This is the power of JSX.
When React needs to render a list with a new version, it compares it to the old version and see if there any item that needs to be added or omitted to increase efficiency and prevent rendering the whole list again.
React does this by keys.
- You need to add a key for the list in the outer (parent) tag.
- The key should be unique:
- if the data comes from database, use the primary keys of the items.
- if it is generated in the runtime you might consider
uuidpackage.
So to correct the last code snippet, we need to add a key for React, it can be the id in the product object:
const productElements = products.map((product) => {
// Now we will add key attribute in the div tag
return (
<div key={product.id}>
<h3>{product.name}</h3>
<p>Price: ${product.price}</p>
</div>
)
})There is a common approach for keys selection which is array index, this approach is simple and map() function provides index as a second arguement, but before using it you must be sure about those things:
- There isn't a unique key: There is no need for using index kinstead of a unique key that already exists.
- List is completely static: You must be sure there are no items being added or deleted.
- List is never reordered or filtered: This is because of the way React render lists as mentioned in the previous section.
Examples for lists that satisfy those conditions: Navigation menu.
We can style components with the style attribute:
export const Alert = ({ children }) => {
return (
<div style={{
backgroundColor: black;
}}>{children}</div>
)
}The first curly braces for embedding JS object inside JSX, the second one is for the object itself.
This method can get messy very fast if the styling increases, so we separate the styling in a css module, As if we didn't make it a module it will be global.
import styles from './Alert.module.css'
export const Alert = ({ children, type = "success" }) => {
return (
<div className={`${styles.alert} ${styles[type]}`}>{children}</div>
)
}We wrote styles[type] as type is dynamic class.
There is 2 simple steps for responding to events:
- Define a function that should be executed when the event occurs.
- Assign this function to a special prop
On.
You can also access the event object and extract useful info about the event in the function you defined.
export const CustomButton = () => {
const handleClick = (e) => { // e is the event object
alert('Thanks for clicking')
console.log(e.target)
console.log(e.button)
}
return (
<button onClick={handleClick}>Click</button>
)
}We can also pass the handler function by props if we need to reuse the button for more than one component.
export const MenuItem = ({ name, price, onOrder }) => {
return (
// Code
<button onClick={() => onOrder(name, price)}>Order</button>
)
}Until now, we still don't update the screen WHY?
- Changing the values of variables doesn't update the screen.
- Every time the component renders (the page reloads), all variables reset to their initial values.
To solve this problem, React provides state, it is the component's memory.
Wecan se the useState() hook that React provides, it returns the current state and the setter function and takes in its arguements initial state.
-
Initial state can be:
- The initial value of the variable we want to update
- An arrow function, it is called
Lazy initialization, React calls this function on component render only and that is when we want to calculate the initial state.
-
Note: If you used the same component that has state twice, updating one will NOT effect the other.
const [count, setCount] = useState(0)
const handleCount = () => {
setCount(count + 1)
}