In this article, I want to share some details to take care of, which will make us better React developers
Separate logic from JSX
- It's always good to spread the logic (or functional part) from the JSX, the code will be cleaner and more editable, check the example below how to handle an onClick event instead of putting it directly inside the element
import React from 'react';
function Todo() {
let condition = true;
const addHandler = () => {
if (condition) {
//do api call
}
}
return (
<div>
<button
onClick={() => addHandler()}
>Add</button>
</div>
)
}
export default Todo;
Split into small components & make them reusable
- In this part let's try to split a UI component from a real project
- NavBar: Top navbar container which contains the HamBtn
- HamBtn: The 3 horizontal lines button, that can be used in other parts
- TodoRow: Todo row, containing the text, and other action buttons
- RadioBtn: Toggle button
- DeleteBtn: Delete button for todo
- Button: Generic button component with several dynamic props
- Container: The whole container for the Todo list.
All these will be separate components, this will help us in the long run, if the project becomes bigger almost all the components can be reused 😎
State Management (Redux or Context)
In the case of using Redux Library, I highly recommend using Sagas which will help you to make async API calls
Redux: Perfect for larger applications where there are high-frequency state updatesAnd for Context Api, its much simple than the Redux, and you don't need to download any library
Context API: Resourceful and ideal for small applications where state changes are minimal
Hooks and Functional Components
- No more "this"
- Fewer lines of code
- It's easier to debug, test & refactor it
I think the majority of developers are already using all their projects based on these two, but I just wanted to mention it 😁
Styled-Components
- Styled-Components is one of the new ways to use CSS in modern JavaScript
- It is meant to be a successor of CSS Modules, a way to write CSS that's scoped to a single component, and not leak to any other element on the page
import React from 'react';
import { Text } from './SubTitle.styled';
function SubTitle() {
return (
<Text>Hello</Text>
)
}
export default SubTitle;
import styled from "styled-components";
export const Text = styled.span`
color: #AAA;
font-size: 20px;
`;
Testing
- Unit Testing - (to check a single component of an application, for more critical functions)
- Integration Testing - (to check if different pieces of the modules are working together)
- End-to-End Testing - (involves testing an application's workflow from beginning to end, aims to replicate real user scenarios)
Typescript
TypeScript is a “typed superset of JavaScript that compiles to plain JavaScript.”
Using Typescript in React will help you to develop more stable components, that are strongly typed and are faster to be integrated, lets check the simplest example
interface Props {
label: string;
onClick: () => void;
}
function Button({ label, onClick, ...props }: Props) {
return (
<button
onClick={onClick}
{...props}
>
{label}
</button>
)
}
export default Button;
Intrinsic elements:
Intrinsic elements are looked up on the special interface JSX.IntrinsicElements. By default, if this interface is not specified, then anything goes and intrinsic elements will not be type checked. However, if this interface is present, then the name of the intrinsic element is looked up as a property on the JSX.IntrinsicElements interface.
Intrinsic elements will allow us to use the native 'props' of an element
export type Props = JSX.IntrinsicElements["button"] & {
label: string;
}
<Button
label={'SUBMIT'}
onClick={() => console.log('CLICK')}
onBlur={() => console.log('BLUR')}
/>
React is an awesome library, you can split & organize your code in a way to become very flexible & scalable, wanted to keep it simple & high-level
Wish it was helpful and that's it 😊
Top comments (10)
These are really some great best practices to follow, usually, I forget to split the components and make them reusable thank you for reminding me. While I was learning more about how to use code effectively, I came across a blog and I must say anyone reading here should also read this blog tatvasoft.com/blog/reactjs-best-pr... to learn more best practices.
There's a small caveat with using
JSX.IntrinsicElements
, which is that it always includes aref
prop, even though it won't work in reality. This type is also referring to a legacy type for class-based components (LegacyRef<T>
).The better choice would be to use
React.[Element]HTMLAttributes<HTML[Element]Element>
, where[Element]
is replace with the element type that your component wraps over, or the more explicitComponentPropsWithRef<"button">
/ComponentPropsWithoutRef<"button">
.I prefer the former, since you don't have to think about updating the type of your Props in case you either wrap or unwrap your component
forwardRef
, which will return the correct type.To explain further: Using
JSX.IntrinsicElements
will give you incorrect type information for props:Passing anything to
ref
will throw a warning in development mode:This is because it has not been forwarded by our wrapper component.
It also refers to the incorrect type
LegacyRef<T>
which acceptsstring
which are legacy as mentioned in the Ref and the DOM.It's by built-in JSX elements to be backwards-compatible with earlier versions of the React API.
However, using the
React.[Element]HTMLAttributes<HTML[Element]Element>
instead:Gives us the correct type information; that
ref
is not present since it doesn't take any refs.If you'd like to accept a
ref
and pass it down to the underlying element, you want to useforwardRef
:Note that the type for
ref
prop is nowRef<T>
, which conforms correctly to whatuseRef
andcreateRef
returns (RefCallback<T> | RefObject<T>
).Hope this helps :-)
How do test components with hooks?
There are some complex interactions that might be just outside of automated testing, so I personally use Storybook so I can manually test hard-to-reach edge cases.
This especially helps when you need a sandbox of real-world state (like connecting to apis and websockets to run through production scenarios without impacting deployments or full-blown application e2e)
Check Jest & Enzyme Libraries, Both are specifically designed to test React applications :)
One question, what you think about Context API with React Query Library and Unstated-next for a large application?
Used before Context API with GraphQL though, the code was much simpler and cleaner, I believe in order to choose which state management to use we need to check the whole app state & how much we have global data. Yep and regarding the Unstated-next it's a good library that can be integrated with Context API.
I'd advocate for a provider-less state tool like zustand (given the state is global)
github.com/pmndrs/zustand
Though, I can see the benefit of the provider pattern if you want multiple scoped states...
React query is great, and keep in mind there is also SWR
swr.vercel.app/
EDIT: After looking at unstated-next, I heavily support its usage in cases where you want multiple instances of a state (maybe you have separate thread management for a messaging app, and you want those states isolated).
I push for zustand for global state and unstated-next for localized state.
Interested
Nicely done! I would suggest to read this one: webman.pro/blog/react-best-practices/