Introduction
Alright folks, it is time for another article providing with you some knowledge you can immediately use to improve your React game to help you become better React devs, write better code or excel at coding interviews.
Use React Hooks In Functional Components
Hooks have been introduced with React v16.8 and are a huge boost for functional programming within React. With hooks, you can and should now make use of functional components instead of class components. But wait...functional components and state? And what's with lifecycle methods?
Have no fear - React Hooks have that covered for you. Let's see some examples:
class myComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '',
};
}
onChange = event => {
this.setState({ value: event.target.value });
};
render() {
return (
<div>
<h1>This is a random class component</h1>
<input
value={this.state.value}
type="text"
onChange={this.onChange}
/>
<p>{this.state.value}</p>
</div>
);
}
}
This was the traditional way using a class. But with hooks we can now do it like this using the useState Hook:
const myComponent = () => {
const [value, setValue] = React.useState('');
const onChange = event => setValue(event.target.value);
return (
<div>
<h1>This is a random functional component with state!</h1>
<input value={value} type="text" onChange={onChange} />
<p>{value}</p>
</div>
);
};
Looks simpler? It is! We are using the useState Hook to set the initial state to an empty String ('') and it returns an array with the current state(value) and a method to mutate that state(setValue). We are also using array destructuring to get access to [value, setValue].
Functional components don't have access to lifecycle methods by default. But now we got hooks and the useEffect Hook comes to our rescue. First the traditional way using a class:
class myComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: localStorage.getItem('someRandomValue') || '',
};
}
componentDidUpdate() {
localStorage.setItem('someRandomValue', this.state.value);
}
onChange = event => {
this.setState({ value: event.target.value });
};
render() {
return (
<div>
<h1>Just some random class component!</h1>
<input
value={this.state.value}
type="text"
onChange={this.onChange}
/>
<p>{this.state.value}</p>
</div>
);
}
}
And here is the same example making use of the useEffect Hook:
const myComponent = () => {
const [value, setValue] = React.useState(
localStorage.getItem('someRandomValue') || '',
);
React.useEffect(() => {
localStorage.setItem('someRandomValue', value);
}, [value]);
const onChange = event => setValue(event.target.value);
return (
<div>
<h1>Some random functional component with state and side Effects!</h1>
<input value={value} type="text" onChange={onChange} />
<p>{value}</p>
</div>
);
};
How awesome is that? useEffect will aways run when one of the values in the passed array [value] changes.
These are just two examples of using React Hooks. There are more out there and you can even create you own custom hooks. Every ReactJS Dev should learn this concept in my opinion!
Use The React Context API For Passing Props
Maybe you have already experienced a situation where you have deeply nested components with a need to pass down props from the higher tier to the lower tier with some components sitting in the middle that are just letting those props pass. Instead of editing each component in the chain you can make use of the React Context API.
In this example, we create a new context in a separate file like:
import React from 'react'
const AuthContext = React.createContext({})
export const AuthProvider = AuthContext.Provider
export default AuthContext
Then we need to wrap the parent element, hence the highest tier from where we want to distribute props with the provider we created:
import React from 'react'
import ChildComponent from './components/ChildComponent'
import { AuthProvider } from './context/AuthContext'
function ParentComponent() {
const auth = { userId: '123456', loggedIn: true }
return (
<AuthProvider value={auth}>
<ChildComponent />
</AuthProvider>
)
}
Now all of the ParentComponent's children have access to auth as a prop. How cool is that?
Now all we have to do is to consume the context in a child component. I'll make use of functional components and the useContext Hook to do so:
import React, { useContext } from 'react'
import AuthContext from './context/AuthContext'
function ChildComponent() {
const auth = useContext(AuthContext)
console.log(auth) // { userId: '123456', loggedIn: true }
return null
}
If there were more child components nested they would have access to the context as well. Awesome!
Styled-Components
Styled-Components belong effectively to the CSS-in-JS libraries that abstract the CSS to component level using only JavaScript to describe styles. They can be created via the ES6 Template Literal Notation using back-ticks like so:
// install styled components with npm install styled-components
import styled from 'styled-components';
const MyButton = styled.button`
background: ${props => props.primary ? "green" : "white"};
color: ${props => props.primary ? "white" : "green"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid green;
border-radius: 3px;
`;
render(
return {
<div>
<MyButton>Normal</MyButton>
<MyButton primary>Primary</MyButton>
</div>
}
)
Now you have a custom styled Button Component that you can use all over in your application instead of the normal HTML button. All styles are encapsulated and won't interfere with other styles in the DOM. That's pretty sick, right?
React Fragments
For a long time you would have to wrap everything in a return statement into a single div for react to render it correctly into the DOM or make use of array notation. Examples:
const myComponent1 = () => {
return
<div>
<Card key="1" />,
'Some Text',
<Card key="2" title="someTitle" content="Just some Content" />
</div>
}
const myComponent2 = () => {
return [
<Card key="1" />,
'Some Text',
<Card key="2" title="someTitle" content="Just some Content" />
]
}
With the introduction of react Fragments you no longer have to use either of this two methods but can instead do something like this:
const myComponent1 = () => {
return
<Fragment>
<Card key="1" />,
'Some Text',
<Card key="2" title="someTitle" content="Just some Content" />
</Fragment>
}
or even this since Babel 7:
const myComponent1 = () => {
return
<>
<Card key="1" />,
'Some Text',
<Card key="2" title="someTitle" content="Just some Content" />
</>
}
That's cool, right?
Use Error Boundaries
Having errors in your application is one thing but if they appear in the View at least they should not break the whole application. For this case "Error Boundaries" have been implemented into React. These are basically components that you can use to to wrap other components. They will then catch errors during rendering and in lifecycle methods down the tree. Via the componentDidCatch method (note that there is no React Hook for this yet so you have to youse a class based component) you can then react to the error and render a fallback or log the error. Here is a short example:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
// using state to initiate a fallback UI render
this.setState({ hasError: true });
// You can also log the error, for example to a service
logErrorToMyService(error, info);
}
render() {
if (this.state.hasError) {
// Rendering the actual fallback UI
return <h1>This error is unknown - too bad!.</h1>;
}
return this.props.children;
}
}
You can now use this ErrorBoundary component like so:
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
React & Typescript
Typescript is a really hot topic and one of the developers top choice to learn in the near future. With the newer versions of create-react-app (CRA) it comes with built-in Support for Typescript. You just have to add the --typescript flag when creating a new project with CRA like so:
npm create-react-app my-app --typescript
The key benefits of using Typescript with React are:
- Latest JavaScript features available
- Interfaces for complex type definitions
- VS Code was made for TypeScript
- Readability and Validation to avoid bugs during development
Here is a simple example of using TypeScript in a functional React Component:
import * as React from 'react';
const MyComponent: React.FunctionComponent<{
name: string
}> = (props) => {
return <h1>{props.name}</h1>
}
export default myComponent;
or with an interface:
interface Props {
name: string
}
const MyComponent: React.FunctionComponent<Props> = (props) => {
return <h1>{props.name}</h1>
}
If you want to learn something new in 2020, definitely give TypeScript a go!
Jest + Enzyme for Testing
Testing your applications is something every dev should do and it is mandatory in many corporations. Testing React apps can be really cool with the right setup. A widely-used setup consists of Jest + Enzyme. Have a look!
Jest comes bundles with create-react-app by default and is a test runner, assertion library and mocking library. It also provides snapshot testing which basically creates a rendered snapshot of a component that will automatically be compared to previous snapshots. If those two don't match the test will fail.
This is really cool for unit tests, integrations tests but what is with real components of your React App? Enter Enzyme, a testing library for React Components developed and maintained by Airbnb and the ideal partner for Jest.
With these libraries in place we can do neat tests like:
it("will render correctly", () => {
const wrapper = shallow(
<MyComponent />
)
expect(wrapper).toMatchSnapshot();
})
to test the basic rendering behaviour of one of our components. But we can do even more stuff, for example testing for props:
// We need to mock zum props first
const user = {
name: 'ThePracticalDev',
email: 'TPD@dev.to',
username: 'tpd',
image: null
}
// Then the tests
describe ('<UserProfile />', () => {
it ('contains h3', () => {
const wrapper = mount(<UserProfile user={user} />)
const value = wrapper.find('h3').text()
expect(value).toEqual('ThePracticalDev')
})
it ('accepts user props', () => {
const wrapper = mount(<UserProfile user={user} />);
expect(wrapper.props().user).toEqual(user)
})
})
This looks awesome, right? And there is so much more you can do with this setup like mocking API calls or testing lifecycle methods...
Conditionals in JSX
Writing JSX is really cool and one of the main features of React. To improve your capabilities you can make use of this little trick:
Instead of using
{ return loginAttempts < maxAttempts ? <MyComponent/> : null }
you can do a short-circuit evaluation
{ return loginAttempts < maxAttempts && <MyComponent/> }
Higher Order Components
Higher Order Components (HOC) are an advanced React concept used to abstract shared code to make it accessible where needed. This concept is similar to higher-order functions in JavaScript so HOCs basically take components and return components but are not components themselves but functions. On an abstract level this looks like:
const MyNewComponent = (MyBaseComponent) => {
// ... copy old component, add additional data/functionality and update
return UpdatedComponent
}
A good example is "connect" from Redux. And a more practical example could look like this:
const colorizeElement = Element => props => <Element {...props} color="blue" />
At first we create the HOC (colorizeElement) with an element that keeps all its props and gets a new prop for the color (blue). Wen can use that HOC to create a new, blue-colored button like:
const MyButton = () => {
return <button>I am a Button</button>
}
const ColoredButton = colorizeElement(MyButton)
function MyComponent() {
return (
<div className="MyComponentClass">
<h1>Hello you colored Button</h1>
<ColoredButton />
</div>
)
}
Looks really cool, right?
React DevTools
React DevTools is a cool browser extension available for Chrome and Firefox and maintained by the Facebook React Core Team. Version 4 came out in August 2019 and this extension is really useful for any React dev.
It works well with react and React Native and really helps you understand what happens inside your react App.
Whats really cool and you may not be aware of this - some big companies like Airbnb and Netflix are using React if you visit their websites you can find information about their sites in your browser console if you have the React DevTools installed:
It is always nice to see what the big players are doing. The same thing can be applied to Redux DevTools!
Bonus: Must-have VS Code Extensions for React Devs
Alright, you have made it all the way down to this point. Time for a little bonus. I have identified some of the best VS Code Extensions for React Devs:
ES7 React/Redux/GraphQL/React-Native snippets
A really cool extensions with almost 4 million downloads that brings you tons of code snippets for everything React, Redux and GraphQL.
Jest / Jest Snippets
Two extensions that harmonize perfectly with Jest and provide you snippets for better testing
Typescript React code snippets
A cool extension that helps you if you work with Typescript + React.
While these are some extensions specifically for React development you should also use the more general ones. If have written an article about the 10 best VS Code Extensions for Frontend Devs in 2020, make sure to check those out as well!
Conclusion
Well, everything comes to an end and this is it for this article. I hope I could give you some insights to become better React Devs regardless if you are just starting out or are an experienced developer already. If you are also into Vue development like me you should really check out my other post about 10 Tips & Tricks to make you a better VueJS Developer I would love to hear your opinions and other important aspects so feel free to leave a comment and also follow me for more upcoming posts!
Top comments (13)
In the end I've understood Hooks. Thank you very much!
P.s. trick with JSX conditions is really cool)
Glad it helped you! :)
Note that hooks make a lot of higher-order components unnecessary. A lot of what was previously done using HOCs can now be done using hooks, as you can make your own custom hooks (they're just functions). Libraries like Relay are moving towards hooks, and the Redux use case you mentioned could also be done with hooks.
For testing, I'd personally recommend react-testing-library over Enzyme: testing-library.com/docs/react-tes...
Valid points - thanks for sharing !
I'm very new to React. Since I've been learning JS functional programming from before, some of the implementations in React is not so difficult to understand.
But I'm finding the concepts like "Hooks", "Redux", "ContextAPI" needs more practice to get hang of it. Thank you so much for the article, really helped me understand the implementations.
Understanding functional programming in JavaScript will always help. Frameworks will come and go, but JavaScript will stay. Glad you like it :)
These tips really help organize the huge mountain of concepts that is React into a manageable number of key ideas. As someone who's trying to understand React better, I appreciate it! <3 If I may return the favor, my team recently created a post with a similar purpose, listing the top productivity tips of contributors such as Kent C. Dodds, vjeux and Emma Wedekind. I think we would make a powerful combo: Productivity Tips from 25 React Experts
The Context API and HOC sections were awesome! Thanks for putting this post together.
Thanks.😊
Always:)
Thank you, I will apply your tips in my next projects. 👍
Cool :)
Nice article. Helped me understand Hooks better!