npx create-react-app myapp
cd myapp
npm start
function App() {
const firstName = "Ahmed";
const lastName = "khaled";
const age = 21;
const job = "Student";
const detailsInput =
<input placeholder = "Enter your details">
</input>;
return (
<div className="App"> <!--must be wrapped in one enclosing tag-->
<h3>Full Name: {firstName} { lastName}</h3>
<h3>Age: { age}</h3>
<h3>Job: {job} </h3>
{detailsInput}
</div>
);
}
import "./App.css" //if we want external CSS file
function App() {
const blog = {
title: "Blog Title 1",
description:"Lorem Ipsum Dolor Lorem Ipsum Dolor Lorem Ipsum Dolor"
}
//styles Object
//CSS Properties are written in camelCase
//This is the inline style method
const styles = {
margin: "16px",
borderRadius: "5px",
padding: "16px",
boxShadow: "0 2px 5px #ccc",
boxSizing:"border-box"
}
return (
<div className="App">
<div style={styles}>
<h3>{blog.title}</h3>
<h3>{blog.description}</h3>
</div>
<hr></hr>
<div style={styles}>
<h3>{blog.title}</h3>
<h3>{blog.description}</h3>
</div>
<hr></hr>
<div style={styles}>
<h3>{blog.title}</h3>
<h3>{blog.description}</h3>
</div>
</div>
);
}
function App() {
const styles = {
margin: "16px",
borderRadius: "5px",
padding: "16px",
boxShadow: "0 2px 5px #ccc",
boxSizing:"border-box"
}
const blogArr = [
{
id:1,
title: "Blog Title 1",
description:"Lorem Ipsum Dolor Lorem Ipsum Dolor Lorem Ipsum Dolor"
},
{
id:2,
title: "Blog Title 1",
description: "Lorem Ipsum Dolor Lorem Ipsum Dolor Lorem Ipsum Dolor"
},
{
id:3,
title: "Blog Title 1",
description: "Lorem Ipsum Dolor Lorem Ipsum Dolor Lorem Ipsum Dolor"
}
];
const blogCards = blogArr.map((item) => {
return (
<div style={styles} key={item.id}>
<h3>{item.title}</h3>
<h3>{item.description}</h3>
</div>
)
})
return (
<div className="App">
{blogCards}
</div>
);
}
import React from "react"
const BlogCard = (props) => {
return (
<div style={props.style}>
<h3>{props.title}</h3>
<h3>{props.description}</h3>
</div>
)
}
export default BlogCard;
## In Default export you can import the item with any name,
but in named export — export {BlogCard} — you must import it with the same name
but you can use alises using "as" —import {BlogCard as Blog item } from "./BlogCard.js"
import BlogCard from './BlogCard';
function App(){
...
const blogCards = blogArr.map((item,pos) => {
return (
<BlogCard id={item.id} title={item.title} description={item.description} style={ styles} />
)
})
return (
<div className="App">
{blogCards}
</div>
);
}
.blogCard {
margin: 16px;
border-radius: 5px;
padding: 16px;
box-shadow: 0 2px 5px #ccc;
box-sizing: border-box;
}
import React from "react"
import classes from "./BlogCard.module.css" //
const BlogCard = (props) => {
return (
<div className={classes.blogCard}> //
<h3>{props.title}</h3>
<h3>{props.description}</h3>
</div>
)
}
export default BlogCard;
These methods are called in the following order when an instance of a component is being created and inserted into the DOM:
- constructor()
- static getDerivedStateFromProps()
- render()
- componentDidMount() If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
An update can be caused by changes to props or state. These methods are called in the following order when a component is being re-rendered:
- static getDerivedStateFromProps()
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
This method is called when a component is being removed from the DOM:
These methods are called when there is an error during rendering, in a lifecycle method, or in the constructor of any child component.
A simple Stateless button component that depends on props only:
And a Stateful counter component example (using Button
component):
As you can see, the last one’s constructor holds a component state, while
the first one is a simple component that renders a text via props. This
separation of concerns may look simple but makes Button
component highly reusable.
<BlogCard
id={item.id}
title={item.title}
description={item.description}
style={this.styles}
likeCount={item.likeCount}
onLikeBtnClick={() => { this.onLikeBtnClick(pos) }} //here
/>
const Home = () => {
const [name,setName] = useState("Ahmed");
const handleClick = ()=>{
setName("Khaled");
}
...
}
React hook called each time the DOM is rendered,but if we want to trigger it for the first time only or when changing a certain state, it's time for dependencies.
const [name, setName] = useState("Ahmed");
useEffect(() => {
console.log("useEffect ran");
}, [name]);
return (
<div className="home">
<p>{name}</p>
<button onClick={() => setName("Khaled")}>Change Name</button>
</div>
);
}
npm install -g json-server
npx json-server --watch data/db.json --port 8000
useEffect(() => {
fetch('http://localhost:8000/blogs')
.then(blogs => blogs.json())
.then(data => setBlogs(data));
},[])
import { useEffect, useState } from "react";
import BlogList from "./BlogList";
const Home = () => {
const [blogs, setBlogs] = useState(null);
const [isPending, setIsPending] = useState(true);
// const handleDelete = (id) => {
// fetch('http://localhost:8000/blogs/' + id, { method: 'DELETE' })
// }
useEffect(() => {
setTimeout(()=>{ fetch('http://localhost:8000/blogs')
.then(blog => blog.json())
.then(data => {
setBlogs(data)
setIsPending(false);
})},1000)
}, [])
return (
<div className="home">
{isPending&&<div className="spinner-border text-danger" role="status">
<span className="sr-only">Loading...</span>
</div>}
{blogs && <BlogList blogs={blogs} title="All Blogs" />}
</div>
);
}
export default Home;
useEffect(() => {
setTimeout(() => {
fetch('http://localhost:8000/blogs')
.then(blog => {
if (!blog.ok) {
throw Error("Couldn't fetch data from server");
}
return blog.json()
})
.then(data => {
setBlogs(data)
setIsPending(false);
setError(false);
}
)
.catch(err => {
setIsPending(false);
setError(err.message);
})
}, 1000)
}, [])
import { useState, useEffect } from "react";
const useFetch = (url) => {
const [data, setData] = useState(null);
const [isPending, setIsPending] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setTimeout(() => {
fetch(url)
.then(blog => {
if (!blog.ok) {
throw Error("Couldn't fetch data from server");
}
return blog.json()
})
.then(data => {
setData(data)
setIsPending(false);
setError(false);
}
)
.catch(err => {
setIsPending(false);
setError(err.message);
})
}, 1000)
}, [])
return { data, isPending, error };
}
export default useFetch;
Single-page applications (SPAs) rewrite sections of a page rather than loading entire new pages from a server.
Twitter is a good example of this type of application. When you click on a tweet, only the tweet’s information is fetched from the server. The page does not fully reload:
These applications are easy to deploy and greatly improve the user experience. However, they also bring challenges.
The React Router API is based on three components:
<Router>
: The router that keeps the UI in sync with the URL.Only one child element<Link>
: Renders a navigation link<Route>
: Renders a UI component depending on the URL
In a web application, you have two options:
- , which uses the HTML5 History API.
- , which uses the hash portion of the URL (window.location.hash)
If you’re going to target older browsers that don’t support the HTML5 History API, you should stick with <HashRouter>
, which creates URLs with the following format:
http://localhost:3000/#/route/subroute
Otherwise, you can use <BrowserRouter>
, which creates URLs with the following format:
http://localhost:3000/route/subroute
if we know that only one route will be chosen, we can use a component to render only the first route that matches the location
npm install react-router-dom@5
...
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
function App() {
return (
<Router> {/*Surround all page with Router tag*/}
<div className="App">
<Navbar />
<div className="content">
<Switch> {/*Inside switch is the part we want to change when turning into new router */}
<Route exact path="/">{/*exact : to match exactly '/' , path:is the route */}
<Home />
</Route>
<Route path="/create">
<Create />
</Route>
<Redirect to="/"/>
</Switch>
</div>
</div>
</Router>
);
}
To prevent browser from sending requests to server while navigating to new route , we use component instead of :
<Link to="/">Home</Link>
{/*instead of <a href="/">Home</a> */}
<Route path="/blogs/:id">
<BlogDetails />
</Route>
To access id in other files use hook useParams from react-router-dom to use it in fetching appropriate data
const { id } = useParams();
const history = useHistory();
history.push('/'); //redirects to home route
fetch(url,{
method:'POST',
'Content-Type':'application/json',
body:blog}).then(()=>{console.log("....")});
//Firstly in ThemeContext.js
import React, { createContext, Component } from 'react';
export const themeContext = createContext();
class ThemeContextProvider extends Component {
state = {
isLightTheme: true,
light: { syntax: '#555', ui: '#ddd', bg: '#eee' },
dark: { syntax: '#ddd', ui: '#333', bg: '#555' },
}
render() {
return (
<themeContext.Provider value={{ ...this.state }}>
{this.props.children}
</themeContext.Provider>
);
}
}
export default ThemeContextProvider;
//inside component wanting to access this context
import React, { Component } from 'react';
import { themeContext } from '../contexts/ThemeContext';
class Navbar extends Component {
static contextType = themeContext;
render() {
const { isLightTheme, light, dark } = this.context;
const theme = isLightTheme ? light : dark;
return (
<nav style={{ background: theme.ui, color: theme.syntax }}>
<h1>Context App</h1>
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</nav>
);
}
}
export default Navbar;
//another approache
import React, { Component } from 'react';
import { themeContext } from '../contexts/ThemeContext';
class Navbar extends Component {
render() {
return (
<themeContext.Consumer>{(context) => {
const { isLightTheme, light, dark } = context;
const theme = isLightTheme ? light : dark;
return (
<nav style={{ background: theme.ui, color: theme.syntax }}>
<h1>Context App</h1>
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</nav>
);
}}
</themeContext.Consumer>
)
};
}
export default Navbar;
import React, { useContext } from 'react';
import { themeContext } from '../contexts/ThemeContext';
const BookList = () => {
const { isLightTheme, light, dark } = useContext(themeContext); //u can use it as many times as u want
const theme = isLightTheme ? light : dark;
return (
<div className="book-list" style={{ background: theme.bg, color: theme.syntax }}>
<ul>
<li style={{ background: theme.ui }}>the way of kings</li>
<li style={{ background: theme.ui }}>the name of the wind</li>
<li style={{ background: theme.ui }}>the final empire</li>
</ul>
</div>
);
}
export default BookList;
It's used to avoid nesting more of nodes in the dom while using components , we can use it as <React.Fragment><\React.Fragment> or <><> , the first one accept key property.
<React.Fragment>
<h1 >Reading List</h1>
</React.Fragment>
React.PureComponent
implements it with a shallow prop and state comparison.
If your React component’s render()
function renders the same result given the same props and state, you can use React.PureComponent
for a performance boost in some cases.
React.memo is a higher order component.It's the functional-component version pf PureComponent class.
With uncontrolled input values, there is no updating or changing of any states. What you submit is what you get.
With controlled inputs, there is always some sort of change going on. The value of the input field will almost always be a prop of the class component (usually a state). Going along with this, there will also be a callback that is necessary to handle the changes going on with the input field.
const titleRef = useRef();
...
<input ref={titleRef} required id="title" className="form-control" />
...
//we can access this node by
titleRef.current
Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.
ReactDOM.createPortal(child, container)
The first argument (child
) is any renderable React child, such as an element, string, or fragment. The second argument (container
) is a DOM element.
A higher-order component is a function that takes a component and returns a new component.It's used to share common functionalities among components
//HOC
import { Component } from "react";
const withCounter = (WrappedComponent) => {
class WithCounter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
}
}
incrementCount = () => {
this.setState((prevState) => {
return { count: prevState.count + 1 };
})
}
render() {
return <WrappedComponent {...this.props} incrementCount={this.incrementCount} count={this.state.count} />
}
}
return (WithCounter);
}
export default withCounter;
//usage
import React, { Component } from 'react';
import withCounter from './WithCounter';
class ClickCounter extends Component {
render() {
const { count, incrementCount } = this.props;
return (
<button onClick={incrementCount} className="btn btn-primary">Clicked: {count}</button >
);
}
}
export default withCounter(ClickCounter);
To stop useEffect function fetching data from server after navigationg to new route , we use AbortController:
const abortCont = new AbortController();
...
fetch(url, { signal: abortCont.signal })
...
return ()=>abortCont.abort();