You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
constPORT=4000;app.listen(PORT,()=>{console.log(`Listening on ${PORT}`);});
Using a separate server instance
Sometimes you may want to separate the app from the server itself.
This makes testing easier, and is a good separation of concerns.
// In server.jsconsthttp=require('http');// This is node's built-in http moduleconstapp=require('./app');// Assuming we create our app in app.jsconstserver=http.createServer(app);// We can pass the app to createServerserver.listen(PORT,()=>{console.log(`Listening on ${PORT`}`);});
Middleware
Every callback we define in express is middleware.
Standard middleware function signature
(req,res,next)=>{}
req - The Request object that represents the incoming Request to the server
res - The Response object that represents the outgoing response to the browser
next - A function that will move to the next middleware function in the chain
app.use
app.use is how you register a middleware function with express. Functions are added
to the express app in the order the app.use() functions are invoked. The callback
(middleware) functions aren't called until a new request comes in to the server.
app.use((req,res,next)=>{// this runs when a request comes in.});
app.use can accept a list of middleware functions OR an array of them.
// Two arrow functions.app.use((req,res,next)=>{},(req,res,next)=>{});// Two named functions.app.use(middleware1,middleware2);// An array of middleware functionsapp.use([middleware1,middleware2]);// Or any combination. It's flexible!app.use([middleware1,middleware2],middleware3,(req,res,next)=>{});
The important thing is, you are just giving express function references, the
functions do not get called until a request is made to the server.
Routes - app.get, app.post, etc
Express routes are similar to app.use, but are conditional middleware.
They depend on the HTTP Method and the Path matching in order to run.
The first argument to these routes is the path to match.
app.get('/',(req,res,next)=>{// Runs only for a GET request to / });app.post('/users',(req,res,next)=>{// Runs only for a POST request to /users});
Router
As a way of organizing your router, express includes a router object.
Letting app know about the router and it's prefix.
We can use app.use to tell express about the router and what prefix
all of it's routes will be under.
constapp=express();constuserRouter=express.Router();// every route we create on userRouter will have the prefix `/users`app.use('/users',userRouter);
Defining Routes on the Router
Routers contain the same .use().get() and .post() methods that app does.
However, the path matching matches everything after the router's prefix.
// Passing a middleware to the routeruserRouter.use(middleware);userRouter.get('/profile',(req,res,next)=>{// Runs when the router path matches /profile// excluding the prefix// Example: If the userRouter's prefix was /users// then the full path that matches is /users/profile});
Error handling
Error handling middleware is just like regular middleware but has four parameters
to the callback function.
Make sure you log your errors to the console, otherwise if you have a bug in your
express app, it might be completely hidden from you.
app.use((err,req,res,next)=>{// The first argument will be an error.console.error(err);// This is a good idea});
Common Pitfalls
Not sending anything back from a route
This will cause express to hang forever. Your browser will never get a response.
app.get('/',(req,res,next)=>{// if I don't res.send or res.json// And I don't call next()// This will cause express to hang.});
module.exports=12// Exporting a single numbermodule.exports=function(){}// exporting a single functionmodule.exports={// exporting an objectkey: value}
imports (require)
constvariable=require("module");// Importing a single thingconst{ key }=require("module");// Importing a thing from the exported object using destructuring
ES Modules
exports
exportconstnum=12;// Exporting a named numberexportfunctionfoo(){}// Exporting a named functionexportconstobj={key: value}// Exporting a named objectexportdefault12// Exporting a default numberexportdefaultfunction(){}// Exporting a default functionexportdefault{// Exporting a default objectkey: value}
imports
importvariablefrom"module.js"// Importing a default exportimport{num}from"module.js"// importing a named exportimportvariable{num}// Doing both at once.import{numasnumber}from"module.js"// Renaming a named import (aliasing)
Tip: Always remember to include a key property when rendering a collection
// Remember the key should be a unique valueconstitemComponents=items.map(item=><Itemkey={item.id}item={item}>
);
IMPORTANT: Your component will likely render without any state the first time
This is the most common problem new React developers run into. When you are fetching remote data, your component will first render with no data. So write your code in your component defensively to avoid this.
Use an empty array as initial state when using map
const[items,setItem]=useState();// Whoops, we have undefined state ^^^// We really should use an empty array:// useState([])// This generates an error because we can't// call map on an undefined value of items.constitemComponents=items.map(item=>{<Itemkey={item.id}item={item}/>});
Use a guard clause to avoid rendering
Sometimes if you have no data, it's better to just
render nothing, or a message to the user that the component is
"loading".
constMyComponent=()=>{const[items,setItems]=useState([]);// This is a guard clause, it returns from our// component early if our items array is empty.if(items.length===0){returnnull;// or you might return a loading message// return <div>Loading...</div>}return(// Return our normal JSX here.)}
useState Hook
Defining a piece of state
useState returns an array with two elements, the state itself, and a function
to update the state. It accepts the initial value for the state as an argument
const[thing,setThing]=useState(initialState)
the set function only QUEUES an update
If you try to access the state after you've changed it,
it won't have changed yet. This is because the set function
only queues up a change, it doesn't happen right away.
const[count,setCount]=useState(0)// ...later in the componentsetCount(count+1)console.log(count)// this will still be 0.// On the next render, count will be 1.
the set function can optionally take a callback function
Whatever we return from the callback will be the new state.
It gets passed the previous state value as the first argument.
They must return JSX or null and not interact with anything outside of the
function.
constMyComponent=()=>{const[data,setData]=useState()// You can't do this! It's a side effect!fetch(url).then((response)=>response.json()).then((data)=>setData(data))}
Don't call the set function of useState inside a component
It should always be called in a useEffect or in an event handler.
constMyComponent=()=>{const[message,setMessage]=useState()setData("Hello World")// This is a side effect!// It will actually trigger an endless loop of rendering!}
useEffect takes a callback as it's first argument, and a dependency array as it's second argument
useEffect(()=>{// side effect code goes here},[])// This is the dependency array
The dependency array
The dependency array decides WHEN the useEffect callback will run.
undefined - The callback will run everytime
[] - The callback will run only on the first render.
[somevariable] - The callback will run on the first render and anytime somevariable changes.
Do use useEffect for side effects
Common side effects we should put in a useEffect Hook:
Fetch Calls
Reading or writing to localStorage
Reading or writing Cookies
Accessing a global variable (you should avoid this anyway)
When to not use useEffect
When you are just doing rendering logic or calculating a value
When you have an event listener like a click or submit
Event Handling in React
Events are added to JSX and passed a callback
In DOM you might do this:
button.addEventListener("click",(event)=>{// Do something with the event.target})
In React you add them using attributes on the JSX
return(<buttononClick={(event)=>{// Do something with the event.target}}>
Click Me!
</button>)
It's cleaner to define your event callback externally to the JSX
consthandleClick=(event)=>{// Do something with the event.target}return<buttononClick={handleClick}>Click Me!</button>
Don't call the function in the onClick attribute
// This will run the handleClick right away, instead of waiting// for the click to happen.return<buttononClick={handleClick()}>Click Me!</button>
useContext Hook
The use context hook is used along with a context to pass data deeply into
a React component tree.
importmyContextfrom'./myContext.js';constAncestorComponent=()=>{// Often we'll use useState or useReducer to store the actual state hereconst[message,setMessage]=useState('Hello World');// Then make an object to assign to the provider's value attributeconstcontextValue={
message,
setMessage
};// We are wrapping this around <App> but contexts could// live at any point in the tree.return(<myContext.Providervalue={contextValue}><App/></myContext.Provider>)}
using the useContext hook
This lets us access whatever we stored in the context's provider's value attribute