Components
Class Component Syntax
class ExampleClassComponent extends React.Component {
render() {
return <h1>Example Class Component</h1>;
}
}
Class Components were a major part of React before introducing React Hooks. Although most new projects prefer Functional Components, there are still many React-based projects that are using Class Components.
class ExampleClassComponent extends React.PureComponent {
render() {
return <h1>Example Class Component</h1>;
}
}
To define a Pure Class Component you have to extend React’s PureComponent
.
Functional Component Syntax
function ExampleFunctionalComponent() {
return <h1>Example Class Component</h1>;
}
const ExampleFunctionalComponent = () => {
return <h1>Example Class Component</h1>;
}
Functional Components are the future of React. Despite previously being solely used for stateless UI components, they are now the preferred way of constructing new components.
import { memo } from 'React';
const ExamplePureComponent = memo({ portal }) => {
return (
<h1>Welcome to {portal}!</h1>
);
}
Pure (Functional) Components always generate the same output given the same input (state and props).
Imports/Exports
Default Imports
export default ExampleComponent;
Use the export and default keywords to export a component.
import ExampleComponent from 'path/to/file';
You can import the default exports from a file using the syntax from above.
Named Imports
export const capitalize = word => {
...
};
export const fetchUserData = userID => {
...
};
export const getUserName = userObject => {
...
};
You can export as many named elements from a file as you wish. To do that you need to use the export
keyword without the default
keyword.
import { capitalize, fetchUserData, getUserName } from 'path/to/file';
To import the named exports you need to list them explicitly within curly braces with the names they have been exported with.
import { ExampleComponent as AliasedExampleComponent } from 'path/to/file';
import { capitalize as cap } from 'path/to/file';
To create an alias you can use the as
keyword followed by the new local name, which will be the name under which the imported component will be used in the current context.
import * as AliasedAllImport from 'path/to/file';
You can import all of the named exports from a file by using the * as syntax
.
Props
Using props in Class Components
class PropsExample extends React.Component {
render() {
return <h1>Welcome {this.props.portalName}</h1>;
}
}
The simplest way to use props in Class Components in React. They are read directly from the props object.
class PropsExample extends React.Component {
render() {
const { portalName } = this.props;
return <h1>Welcome to {portalName}</h1>;
}
}
A more efficient way to use props in Class Components is to use the destructuring assignment. We can then use the props directly.
Read more about props in class components.
Efficient props passing
import { useState } from 'react';
import Counter from './User';
function App() {
const [year, setYear] = useState(1237);
return (
<div>
<Counter
currentCount={year + 3}
maxCount={year + (year * 200)}
/>
</div>
);
}
JS expressions will be evaluated and their result will be passed down as props.
import { useState } from 'react';
import Counter from './User';
function App() {
const [year, setYear] = useState(1237)
return (
<div>
<Counter
warning={`Current year is ${year}`}
/>
</div>
);
};
You can use template literals to efficiently build strings.
import User from './User';
function App() {
const user = {
name: 'Tommy',
surname: 'Smith'
};
return (
<div>
<User name={user.name} surname={user.surname} />
<User {...user} />
</div>
);
}
You can spread objects to pass all of their properties as individual props.
Using props in Functional Components
const PropsExample = (props) => {
return <h1>Welcome to {props.portalName}</h1>;
}
With Functional Components, you have to expect props object to be passed from the parent. You can then access the props on the props object.
const PropsExample = ({ portalName }) => {
return <h1>Welcome to {portalName}</h1>;
}
A more efficient way to use props in Functional Components is to use destructuring assignment. We can then use the props directly.
Read more about props in class component
Passing props
const PropsExample = () => {
const userAge = 21;
const isOverEighteen = userAge > 18;
return (
<TargetComponent
portalName="Upmostly"
userAge={userAge}
isOverEighteen={isOverEighteen}
beigeBackground
/>
);
};
You can pass props to the children/target component by assigning them as attributes to the JSX elements one by one.
Children props
const App = () => {
return (
<>
<ParentComponent>
<ul>
<li>This</li>
<li>is</li>
<li>children</li>
<li>element</li>
</ul>
</ParentComponent>
</>
);
};
You can pass the children to components by providing them through JSX. Those need to be located between the opening and closing tags of the elements you wish to pass them to.
const ParentComponent = ({ children }) => {
return (
<div>
{children}
</div>
);
};
To use children you can use the children element on the props object. In the above example, we’re destructuring the object in the component definition and returning the children in JSX.
Default
ExampleComponent.defaultProps = {
name: 'Default name',
surname: 'Default surname',
age: 'Default age',
};
You can define the default props by assigning an object with relevant props to the defaultProps property available on every component.
const User = ({
name = 'Default name',
surname = 'Default surname',
age = 'Default age',
color = 'lightgreen'
}) => {
return (
<div style={{ backgroundColor: color, padding: '10px', marginBottom: '10px' }}>
<h2>Name: {name}</h2>
<h2>Surname: {surname}</h2>
<h2>Age: {age}</h2>
</div>
);
};
Simple application using default props enforced in the component definition.
State
State in Class Components
class UserAccount extends React.Component {
constructor(props) {
super(props);
this.state = {
username: 'mike123',
userAge: 21
};
}
render() {
return (
<div>
<h2>User account</h2>
<ul>
<li>Username: {this.state.username}</li>
<li>Age: {this.state.userAge}</li>
</ul>
</div>
);
}
}
In Class-based Components, you’re instantiating the state values as properties of the state object within the body of the constructor function. You can then use the state variables across your code by accessing them on the this.state
object.
class UserAccount extends React.Component {
constructor(props) {
super(props);
this.state = {
username: '',
};
}
render() {
return (
<div>
<input
type='text'
value={this.state.username}
onChange={(event) => this.setState({ username: event.target.value })}
/>
</div>
);
}
}
To update the state you simply have to call the setState
method accessible via this keyword. As an argument, you have to pass it an object with the new values of the properties that should be updated.
Complex state operations
const [users, setUsers] = useState(['Tom', 'Mike', 'Anna', 'Amy']);
const swapNames = () => {
let usersCopy = [...users]
usersCopy[0] = users[3]
usersCopy[3] = users[0]
setUsers(usersCopy)
};
You can perform complex operations on the arrays stored in the state by creating a copy of the array.
const [person, setPerson] = useState({
name: 'Tom',
surname: 'Smith',
age: 22
});
const updateAge = () => {
setPerson({ ...person, age: person.age - 1 })
};
You can perform complex operations on the objects stored in state by spreading the array and overwriting properties with desired changes, whilst keeping the other changes stored in state as prior.
State in Functional Components
const UserAccount = () => {
const [username, _] = useState('mike123');
const [userAge, setUserAge] = useState(21);
return (
<div>
<h2>User account</h2>
<ul>
<li>Username: {username}</li>
<li>Age: {userAge}</li>
</ul>
</div>
);
};
With Functional Components, you can manage state by using the useState
hook. It returns two values: the first one is the read-only state variable that can be used to access the state value, and the second one is the callback that will be used to update that state variable with the value passed as its argument.
const UserAccount = () => {
const [username, setUsername] = useState('')
return (
<div>
<input
type='text'
value={username}
onChange={(event) => setUsername(event.target.value)}
/>
</div>
);
};
To update the value of the state you can call the second return value from the useState hook. You need to pass it the new value of the desired state as an argument in order to update the current one.
Static data (NOT TECHNICALLY STATE)
const USERNAME = 'mike123';
const UserAccount = () => {
return (
<div>
<h2>Current user: {USERNAME}</h2>
</div>
);
};
If you have some data that won’t be changing over time then you can simply define it outside of your component.
const USER_TYPES = {
ADMIN: 'Admin',
BASIC_USER: 'Basic',
PREMIUM_USER: 'Premium',
VIP_USER: 'VIP',
};
function App() {
const [userType, setUserType] = useState(USER_TYPES.ADMIN)
return (
<div>
<h2>Current user type: {userType}</h2>
</div>
);
}
Enums are a great way to add more structure to your React application. Enums are very often used when a given variable can only take a value that is limited to a subset. They can help us enforce consistency to avoid runtime errors and increase the code readability.
Hooks
useState
import { useState } from 'react';
const App = () => {
const [<state-variable>, <setter-function>] = useState(<default-state>);
return <div></div>;
}
export default App;
When calling the useState
hook you need to pass it the default state value (initial state) for initialization. useState
will return you a tuple containing the read only state variable and the setter function to update the value of the read-only state variable.
import { useState } from 'react';
const App = () => {
const [counter, setCounter] = useState(0);
return (
<div>
<h2>{counter}</h2>
<button onClick={() => setCounter(counter + 1)}>Increment</button>
<button onClick={() => setCounter(counter - 1)}>Decrement</button>
</div>
);
};
export default App;
In the above example, we’re defining the state variable holding our counter variable. We’re also using the setCounter
setter function to handle the incrementation and decrementation of the value of the counter state variable.
useContext
import React, { createContext } from 'react';
...
export const <context-name> = createContext();
ReactDOM.render(
<<context-name>.Provider value={<context-value>}>
<App />
</<context-name>.Provider>,
document.getElementById('root')
);
To define a new context you need to import createContext
from React as a named import. Then you need to save the return value of calling createContext
. The next step is to wrap the part of the application that you wish to be accessible with the Context Provider. Finally, you have to pass the value of the context to the value property.
import { useContext } from 'react';
import { <context-name> } from './index';
...
const <context-variable> = useContext(<context-name>);
console.log(<context-variable>);
To use the context we firstly have to import the useContext
hook and the context variable itself. We can access the value of context by passing the as an argument to the useContext
. The returned value will be the value of the context itself.
useCallback
import { useCallback } from 'react';
const App = () => {
const <memoized-callback> = useCallback(<callback-function>, <dependency-array>)
return <div></div>;
};
The useCallback
hook takes two arguments: the first one is the callback function and the second one is the dependency array. useCallback
will trigger the execution of its callback argument each time any of the elements in the dependency array changes.
import { useCallback } from 'react';
const App = () => {
const [userID, setUserID] = useState(2423);
const computeUserScore = () => {
...
}
const memoizedCallback = useCallback(() => computeUserScore(), [userID]);
...
};
We have written a simple component that computes the user score and returns it. memoizedCallback
will be updated when the userID
changes.
useMemo
import { useMemo } from 'react';
const App = () => {
const <memoized–value> = useMemo(<callback-function>, <dependency-array>);
return <div></div>;
};
useMemo
takes two arguments, the first one is the callback function which computes the desired value and the second one is the dependency array. It works similarly to the useEffect
hook. useMemo
will re-compute the memoized value each time any of the elements passed to the dependency array undergoe any changes.
import { useMemo } from 'react';
const App = () => {
const [userID, setUserID] = useState(2423);
const computeUserScore = () => {
...
};
const userScore = useMemo(() => computeUserScore(), [userID]);
return <div>{userScore}</div>;
};
We have written a simple component which computes the user score and returns it. userScore
is computed by the computeUserScore
function, which is memoized. The score is re-computed only if there is a change to the userID
state variable.
useImperativeHandle
import { useImperativeHandle } from 'react';
const App = () => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
<property>: () => {
...
}
}));
return <input ref={inputRef} />;
};
The useImperativeHandle
hook gives us control over the values exposed to the parent component via the ref handle. From the parent component you can then call inputRef.current()
.
useDebugValue
import { useDebugValue } from 'react';
...
useDebugValue(<label>);
The useDebugValue
hook takes a label that will be displayed when debugging custom hooks.
import { useDebugValue } from 'react';
const useUserStatus = () => {
const [premiumUser, setPremiumUser] = useState(true);
useDebugValue(premiumUser ? 'premium user' : 'basic user');
return premiumUser;
};
In the custom hook useUserStatus
we’re using the useDebugValue
hook to display relevant user status.
useTransition
import { useTransition } from 'react';
function App() {
const [<value>, <function>] = useTransition();
...
}
The useTransition
hook returns a tuple containing a value that indicates whether the transition is running, as well as a function to start the transition.
import { useTransition, useState } from 'react';
function App() {
const [loading, startTransition] = useTransition();
const [count, setCount] = useState(0);
const handleClick = () => {
startTransition(() => {
setCount(count + 1);
})
}
return (
<div>
<h2>{count}</h2>
<button onClick={handleClick}>Increment</button>
{loading && <Loader />}
</div>
);
}
In the above counter example we’re using the loading value to indicate to the users if there is an update happening. We’re also using the startTransaction
function to update the state on every click of the button.
useEffect
import { useEffect } from 'react';
const App = () => {
useEffect(<callback-function>, <dependency-array>);
return <div></div>;
}
The useEffect
hook takes 2 arguments, the first one is a callback function and the other one is the dependency array. The callback function runs every time React detects an update to element (ref or any other piece of state) provided in the dependency array.
import axios from 'axios';
import { useEffect } from 'react';
const App = () => {
useEffect(() => {
const fetchData = async () => {
...
};
fetchData()
}, []);
return <div></div>;
};
We’re calling the fetchData
function that’s responsible for fetching data from the server. We execute it on every re-render because the dependency array is empty.
import axios from 'axios';
import { useEffect } from 'react';
const App = () => {
const [userID, setUserID] = useState(23112);
useEffect(() => {
const fetchData = async (userID) => {
...
};
fetchData(userID)
}, [userID]);
return <div></div>;
}
We’re calling the fetchData
function that’s responsible for fetching data from the server. We execute it only when there was a change in the userID state variable.
useReducer
import { useReducer } from 'react'
const App = () => {
const [state, dispatch] = useReducer(<reducer-function>, <initial-state-object>);
return <div></div>;
};
The useReducer
hook takes two functions as aguments; the first one is the reducer function used to modify the current state held by the reducer and the second one is the initial state object. It returns the state variable that can be used to access the state values and dispatch that triggers state updates.
import { useReducer } from 'react';
const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
}
};
const App = () => {
const [state, dispatch] = useReducer(reducer, {count: 0});
return (
<>
<h2>Count: {state.count}</h2>
<button onClick={() => dispatch({type: 'decrement'})}>Plus one</button>
<button onClick={() => dispatch({type: 'increment'})}>Minus one</button>
</>
);
};
In the above example, we have written a counter example. It is initialized with the reducer function and the initial state object. We’re displaying the current value of the counter to the users and let them change it by interacting with the two buttons. They are calling the dispatch
method with the relevant action object. The reducer function reads the values of the action object and returns the new piece of state.
useRef
Syntax
import { useRef } from 'react';
const App = () => {
const <ref-variable> = useRef();
return <div ref={<ref-variable>} />;
};
To create a new reference you need to import the useRef
hook from React. Then you have to call the hook and save the return value as a variable. Finally you’d have to pass the to the ref prop on the desired JSX element.
import { useRef } from 'react';
const App = () => {
const ref = useRef();
const onClickHandler = () => {
ref.current.focus();
};
return (
<>
<input ref={ref} type="text" />
<button onClick={onClickHandler}>Focus</button>
</>
);
}
In the above example, we have defined a reference and passed it to the input element. We also created a button element. We’re using the reference to call the focus method on it every time we click on the button.
useLayoutEffect
import { useLayoutEffect } from 'react';
const App = () => {
useLayoutEffect(<callback-function>, <dependency-array>);
return <div></div>;
};
The useLayoutEffect
hook takes 2 arguments; the first one is a callback function and the other one is the dependency array. The callback function runs after all the necessary mutations have been applied to the DOM.
useDeferredValue
import { useDeferredValue } from 'react';
const App = ({ value }) => {
const <deferred-value> = useDeferredValue(value);
...
};
The useDeferredValue
hook accepts a value as an argument and returns a deferred value.
import { useDeferredValue } from 'react';
const App = ({ value }) => {
const deferredValue = useDeferredValue(value);
return <div>{deferredValue}</div>;
};
useId
import { useId } from 'react';
...
const id = useId();
After importing the useId
hook from React you can simply assign the value returned by calling the hook to a variable which will then be assigned a generated unique id value.
import { useId } from 'react';
const App = () => {
const id = useId();
return (
<>
<button id={id}>Hello</button>
</>
);
};
We’re generating a new ID and passing it to the JSX.
Lifecycle methods
constructor(props) {
super(props);
this.state = {
portalName: 'Upmostly'
};
this.handleLogin = this.handleLogin.bind(this);
}
A constructor in React is used to initialize state and bind methods inside of the class component.
componentWillUnmount() {
document.removeEventListener("click", this.closeMenu);
}
This is what we call a ‘cleanup‘ method. You can treat it as the opposite of the componentDidMount
. It’s the place in which you should cancel any tasks that you might have initialized when the component was mounting. `componentWillUnmount` is called when the components is removed from the DOM.
getSnapshotBeforeUpdate() {
return {
tableBackground: this.tableRef.current.offsetHeight >= 85
};
}
This method is called shortly before any of the component output gets appended to the real DOM. It helps us capture some information that can be useful when calling componentDidUpdate
.
static getDerivedStateFromProps(props, state) {
if(props.id !== state.id){
return {
id: props.id
}
}
return null;
}
This method is called every time right before the render method.
render() {
return <h1>Welcome to {this.state.portalName}</h1>;
}
Render is a required method that tends to return JSX.
componentDidMount() {
axios.get(testEndpoint).then(resp => this.setState({ testData: resp }));
}
This method is called when the component is first mounted to the DOM. It is typically used to fetch data from other applications.
shouldComponentUpdate(nextProps) {
if (nextProps.portalName !== this.props.portalName) return true
return false;
}
This method is used as something that can help improve the performance of our components. It’s called before the component gets re-rendered with new props or state.
componentDidMount(prevProps) {
if (this.props.ID !== prevProps.ID) {
axios.get(testEndpoint)
.then(resp => this.setState({ testData: resp }));
}
}
This method is called right after the component re-renders. It’s typically used for DOM manipulations or for making more efficient requests to other applications.
JSX
return (
<div>Hello from Upmostly!</div>
);
React components are meant to return a single top-level JSX element.
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}
const App = () => {
const user = {
firstName: 'Mike',
lastName: 'Smith',
};
return (
<div>
{getGreeting(user)}
</div>
);
};
JSX can contain JavaScript expressions, such as function calls. Function calls may return JSX which will be rendered to the screen.
return (
<div>
<h1>Hello from Upmostly!</h1>
<button>Click me</button>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
);
React components are meant to return a single top-level JSX element. That element can have more elements nested within.
const App = () => {
return (
<div className="element-with-class-in-jsx" />
);
};
In JSX, elements can no longer use the “class” keyword, since that’s restricted to JavaScript. Instead, we are using the “className” keyword, which does the same thing as the “class” keyword does in HTML.
Axios
Setup
import axios from 'axios';
To send any request using axios we must first import axios
from the axios
package.
POST
import axios from 'axios';
...
const response = await axios.post(<endpoint>, {
id: userID,
userAge: 22,
userName: ‘Mike’
});
You can use the post method available on it to send the POST request to the endpoint provided as an argument. The second argument will be attached as a payload to the request.
DELETE
import axios from 'axios';
...
const response = await axios.delete(<endpoint>);
You can use the delete method available on it to send the DELETE request to the endpoint provided as an argument.
GET
import axios from 'axios';
...
const response = await axios.get(<endpoint>);
You can use the get method available on it to send the GET request to the endpoint provided as an argument.
import axios from 'axios';
...
const response = await axios.get(<endpoint>, {
paramsOne: paramOneValue,
paramsTwo: paramTwoValue,
paramsThree: paramThreeValue
});
If your request depends on some query params then you can simply pass them as an object as a second argument to the get method. Axios will handle the rest for you.
PUT
import axios from 'axios';
...
const response = await axios.post(<endpoint>, {
id: userID,
userAge: 22,
userName: ‘Mike’
});
You can use the put method available on it to send the PUT request to the endpoint provided as an argument. The second argument will be attached as a payload to the request.
Useful syntax
Conditional operator
<condition> ? <if-true> : <if-false>
Ternaries are a shorthand notation for control flow with 2 conditions. If the condition evaluates to true then the block will run, otherwise the will run.
import { useState } from 'react';
const App = () => {
const [age, setAge] = useState(19)
return (
<div>
<h2>{`User is ${age > 18 ? 'over' : 'under' } 18`}</h2>
</div>
);
}
We’re using the ternary operator to render the correct string. If the user is over 18 then ‘User is over 18’ will be rendered.
Conditional chaining
<object-name>?.[<property-name>]
If the exists on then it will be accessed, otherwise the expression will be evaluated to undefined
.
const user = {
personalDetails: {
name: 'Tommy',
surname: 'Smith',
age: 21
},
subscriptionDetails: {
type: 'premium',
price: 12.99
}
};
user?.subscriptionDetails?.type // premium
user?.subscriptionDetails?.age // undefined
The first expression evaluates to string ‘premium’ while the other one to undefined
.
Profiler
import { Profiler } from 'react';
function App() {
return (
<Profiler id=<string-id> onRender={<log-function>}>
...
</Profiler>
);
}
To use the Profiler
we need to import it from the react package. The next step is to wrap the portion of the JSX tree that you’d like to have analyzed. You then have to pass the that’s used to identify the Profiler and the that will process your log.
import { Profiler } from 'react';
import Counter from './Counter'
const log = (id, phase, actualTime, baseTime, startTime, commitTime, interactions) => {
console.table({ id, phase, actualTime, baseTime, startTime, commitTime, interactions });
};
function App() {
return (
<div style={{ margin: '50px' }}>
<Profiler id="Counter" onRender={log}>
<Counter />
</Profiler>
</div>
);
}
export default App;
In this example, we are using the Profiler
to inspect the data about our custom Counter component. We’re then logging the data in a form of a table to make it easier to understand.
Short circuit evaluation
import { useState } from 'react';
import MyComponent from './component';
const App = () => {
const [age, setAge] = useState(19);
return (
<div>
{age > 18 && <MyComponent />}
</div>
);
}
&& operator is often used to render components if a given condition is met. If the condition is not met then it will evaluate to and return null
.
import MyComponent from './component';
const user = {
personalDetails: {
name: 'Tommy',
surname: 'Smith',
age: 21
},
subscriptionDetails: {
type: 'premium',
price: 12.99
}
};
const App = () => {
return (
<div>
{user?.userDetails || ‘Fallback value’}
</div>
);
};
|| operator is often used to render a fallback value when the condition evaluates to falsy. If the condition is falsy then it will render ‘Fallback value’.
React 18
import ReactDOM from 'react-dom/client';
const rootElement = document.getElementById('root');
const root = ReactDOM.createRoot(rootElement);
root.render(<App />);
The above code snippet will help you to adapt your code to the React 18 changes.
Fragments
import React from 'react';
const Numbers = () => {
return (
<React.Fragment>
<li>1</li>
<li>2</li>
<li>3</li>
</React.Fragment>
)
}
Wrap the JSX siblings within the Fragment
component available on the default React import from React package.
const Numbers = () => {
return (
<>
<li>1</li>
<li>2</li>
<li>3</li>
</>
);
}
Simply next the JSX siblings between the and tags.
Styling
Inline
const App = () => {
return <h2 style={{ fontSize: '10px', color: 'yellow' }}>Hello from Upmostly!</h2>;
};
You can use the inline styling by providing the JSX element with the style prop. It accepts an object whose keys are camelCased CSS properties corresponding to values provided as strings.
Read more about inline styling
Computed Inline Styles
const App = ({ headerFontSize, headerColor }) => {
const styles = {
fontSize: headerFontSize,
color: headerColor,
};
return <h2 style={styles}>Hello from Upmostly!</h2>;
};
Read more about inline styling
CSS modules
import <styles-object> from './<name>.module.css';
...
.heading
font-size: 10px;
}
You can use the CSS modules by naming your CSS files in the .module.css format. You can define your styles just like you would in a regular CSS file.
import styles from './App.module.css';
const App = () => {
return <h2 className={styles.heading}>Hello from Upmostly!</h2>;
};
You can use the CSS modules by importing the styles from the relevant file and passing the desired style to the className
prop of the relevant JSX element.
CSS
import './App.css';
const App = () => {
return <h2 className='header'>Hello from Upmostly!</h2>;
};
You can use the CSS by importing the relevant CSS file into your component. You can then add relevant classes by using the className
property on the relevant JSX element.
Styled-components
import styled from 'styled-components';
const <styled-component-name> = styled.<element>`
<css-properties>
`;
To use styled components you have to first import styled
from the styled-components
package. You can define the new styled component by using the styled.“ syntax. You can provide the desired properties between “ just like you would in any other CSS file.
import styled from 'styled-components';
const Heading = styled.h2`
font-size: 10px;
`;
const App = () => {
return <Heading>Hello from Upmostly!</Heading>;
};
The above code snippet defined a new styled component called Heading
. It then uses the styled component just like any other component in the JSX.
Tricks
Useful React patterns
const FIBONACCI = [1, 1, 2, 3, 5, 8];
const App = () => {
return (
<ul>
{FIBONACCI.map((number) => <li key={number}>{number}</li> )}
</ul>
);
}
You can render arrays in React efficiently by using the map method. You can map each of the elements of the array into its corresponding JSX element and render it directly from the JSX.
Read more about using map in React
const pluralize = (number, singular, plural) => {
if (number === 1) {
return `${number} ${singular}`
}
return `${number} ${plural}`;
};
Your strings might sometimes depend on a numerical value to display a relevant form of the noun. You can write a pluralize
method to handle this for you automatically.
import { useState } from 'react';
const App = () => {
const [users, setUsers] = useState([1]);
return (
<div>
{
users.length === 0
? <h2>There are no users :(</h2>
: <h2>There are {users.length} users :)</h2>
}
</div>
);
}
If your Application depends on the data stored in the array, you can provide a fallback in case the array is empty.
PropTypes
import PropTypes from 'prop-types';
...
ExampleComponent.propTypes = {
<prop-name>: PropTypes.<type>,
...
};
You have to import PropTypes
from the prop-types
package. You can then define the desired types by writing them in an object notation and assigning them to the propTypes
property on your component.
import PropTypes from 'prop-types';
const User = ({ name, surname, age }) => {
return (
<div>
<p>Name: {name}</p>
<p>Surname: {surname}</p>
<p>Age: {age}</p>
</div>
);
};
User.propTypes = {
name: PropTypes.string,
surname: PropTypes.string,
age: PropTypes.number
};
export default User
We’re defining name and surname to be of type string
and age of type number
.
import PropTypes from 'prop-types';
const App = ({ name, age, rightHanded }) => {
return (
<div>
<p>Name: {name.firstName}</p>
<p>Surname: {name.lastName}</p>
<p>Age: {age}</p>
<p>Dominant hand: {rightHanded ? 'right' : 'left'}</p>
</div>
);
};
App.propTypes = {
name: PropTypes.shape({
firstName: PropTypes.string,
lastName: PropTypes.string
}),
age: PropTypes.number,
rightHanded: PropTypes.oneOf([true, false]),
};
export default App;
You can also manage more complex props shapes using PropTypes.
Events on JSX elements
onClick
import { useState } from 'react';
const App = () => {
const [userName, setUserName] = useState('Tommy')
const [showName, setShowName] = useState(false)
return (
<div>
{showName && <h2>{userName}</h2>}
<button onClick={() => setShowName(!showName)}>Show user name</button>
</div>
);
};
You can use the onClick
handler to update the state.
Read more about handling onClick
onChange
import { useState } from 'react';
const App = () => {
const [userInput, setUserInput] = useState('');
return (
<div>
<input value={userInput} onChange={(event) => setUserInput(event.target.value)}/>
</div>
);
};
You can use the onChange
handler to control the data in your inputs.
onSubmit
import { useState } from 'react';
const App = () => {
const [userInput, setUserInput] = useState('');
const submitHandler = (event) => {
event.preventDefault();
console.log(userInput);
}
return(
<div>
<form onSubmit={submitHandler}>
<input value={userInput} onChange={(event) => setUserInput(event.target.value)}/>
<button type='submit'>Submit</button>
</form>
</div>
);
};
You can use the onSubmit
handler to submit your forms. onSubmit
is available on the form tag which has a button on type submit nested.
Event handler short form
import { useState } from 'react';
const App = () => {
const [userInput, setUserInput] = useState('');
const handleInputValueChange = (e) => {
setUserInput(e.target.value);
};
return (
<div>
<input
value={userInput}
onChange={handleInputValueChange}
/>
</div>
);
};
If the event handler function you have defined only takes an event parameter you can just pass it to the event handler prop and the event object will be inferred.
ReactDOM API
Strict Mode
import React, { StrictMode } from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<StrictMode>
<App />
</StrictMode>,
document.getElementById('root')
);
Usage: Import StrictMode
from React and then wrap the part of the application where you would want to use it.
💬 Leave a comment