React development: 6 paths to professional growth

For the past six months, I've been watching the development of aspiring React programmers. During this time, they have passed an incredible path. The speed of their learning, their thirst for knowledge, their desire for excellence - all this made a strong impression on me.



How did they do it? How did they go from those who cannot open PR without outside help to those to whom others turn for help? What has made people asking for advice people willing to give advice to others? How did students become teachers? I asked them these questions. Here's what they answered.











1. Use ESLint and TypeScript



JavaScript is a loosely typed programming language. Using this language, we can solve the same problem in countless ways. JavaScript has no built-in mechanisms to protect us from writing buggy code or code that has poor performance. But, fortunately for us, we can improve the situation by resorting to two tools for static code analysis. These are TypeScript and ESLint.



By using ESLint for static code analysis, we can identify problems before they hit production. We can check the code against our standards. This improves the maintainability of the codebase.



For example, you can install the ESLint plugineslint-plugin-react-hooks... This plugin will notice the problem in the following code, which looks completely normal, and will inform us that we are violating one of the rules for using hooks.



//    ,    
  if (userName !== '') {
    useEffect(function persistForm() {
      localStorage.setItem('formData', userName);
    });
  }


TypeScript allows you to use a static type system to catch related errors. When using TypeScript, you can use the powerful IntelliSense tooltip that makes working with various components and libraries faster and easier. The tooltips that appear as you write your code provide information about the internal mechanisms of components and libraries. This speeds up refactoring and encourages coding conventions like generics.



Someone who is good at TypeScript not only becomes a better JavaScript programmer, but eventually starts writing better React code.



2. Get familiar with React hooks



React Hooks have literally taken over the world of React development since their introduction in February 2019. Although the React team says that you shouldn't refactor old code by translating it into hooks, hooks are literally everywhere these days.



If you want to get ahead in the realm of React development, the best time you can take the time to do is learn hooks in depth so that you can fully understand them.



Do you need some kind of side effect? If so, then the hook useEffectis your best friend. Need to monitor the state of a component and re-render it when the state changes? Take a look atuseState... Need to store and update some values ​​between renders, but when these values ​​change, do not render? Or maybe you need to know about the height or width of DOM elements? Then your friend is this useRef.



For example, let's look at the simplest use case useEffect. Suppose we want to arrange for the page title to update (in the form of a side effect) when a button is clicked. You can try to solve this problem like this:



useEffect(() => {
  document.title = `You clicked ${count} times`;
}); //    


This hook is easy to optimize by making it not run on every render, but only when the variable changes count. This is done by including the countdependencies in the array:



useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); //      count


You should be comfortable using the most common hooks and creating your own hooks. You should also be well versed in the rational use of hooks. For example, knowing when using hooks seems to useEffectresult in re-rendering and when it doesn't.



3. Don't optimize your code too early



The conversation about hooks leads us to the topic of premature optimization. Too often I've seen aspiring React developers go to the bone to make their code as fast as possible. React code is most often optimized using hooks useMemoand useCallback. But their use is not always justified.



Let's take a look at a simple component that takes an array of confectionery information as props. The component filters the array and displays a list of names of chocolates (their property typeis equal to a string value chocolate).



Some developers may have an irresistible urge to write code similar to the one shown below. They might think, "I will only update the list of chocolates when the overall list of confectionery changes." Implementing this idea will result in code overloaded with helper constructs that is difficult to read.



const Chocolate = (props) => {
  const chocolates = useMemo(
    () => props.candies.filter((candy) => candy.type === "chocolate"),
    [props.candies]
  );
  return (
    <>
      {chocolates.map((item) => (
        <p>{item.name}</p>
      ))}
    </>
  );
};


Instead of creating a component like this, I would suggest writing simple and clean code. In cases like this, there is no reason to use useMemo. Hooks useMemoor useCallbackshould be used only for memoizing the results of complex operations that create a large load on the system.



I recommend postponing the start of the optimization work until you get an application performance measurement that clearly indicates a problem.



You should not use it everywhere useCallbackand useMemoonly because you recently read about them somewhere. Don't optimize everything. Better to wait for the problem to appear, and then solve it. Don't solve non-existent problems.



4. Know when to create new components



I've seen many aspiring React programmers implement the business logic of a project in components that are meant to play a purely presentation role. In order to make your code as reusable as possible, it is important to create components that are as easy and convenient as possible to be reused.



To achieve this, you need to strive to maintain separation between presentation components and components that implement some kind of logic. Previously, a common technique was to divide components into "containers" and, in fact, "components". But this approach gradually lost its relevance.



Let's take a look at a component that loads a list of items from somewhere and displays them on the page. Note that both of these tasks are implemented in the same component.



const ListItems = () => {
  const items = React.useState([]);
  React.useEffect(() => {
    async function fetchItems() {
      await fetched = fetchItems();
      setItems(fetched);
    }
  });
return (
    <>
      {items.map((item) => (
        <div className="item-container">
          <img src={item.img} />
          <div className="name">{item.name}</div>
          <div className="author">{item.author}</div>
        </div>
      ))}
    </>
  );
};


It may be tempting to take the "container" route. Following this aspiration, we will come to create two components:



const ListContainer = () => {
  const items = React.useState([]);
  React.useEffect(() => {
    async function fetchItems() {
      await fetched = fetchItems();
      setItems(fetched);
    }
  });
return <List items={items} />;
};
const List = (props) => {
  return (
    <>
      {props.items.map((item) => (
        <div className="item-container">
          <img src={item.img} />
          <div className="name">{item.name}</div>
          <div className="author">{item.author}</div>
        </div>
      ))}
    </>
  );
};


But in such a situation, you should act differently. Namely, you need to abstract those parts of the component that play a purely presentation role. The result will be two components - a component List(list) and a component Item(element):



const List = () => {
  const items = React.useState([]);
  React.useEffect(() => {
    async function fetchItems() {
      await fetched = fetchItems();
      setItems(fetched);
    }
  });
return (
    <>
      {items.map((item) => (
        <Item item={item} />
      ))}
    </>
  );
};
const Item = ({ item }) => {
  return (
    <div className="item-container">
      <img src={item.img} />
      <div className="name">{item.name}</div>
      <div className="author">{item.author}</div>
    </div>
  );
};


5. Pay special attention to testing



The level of proficiency in testing technologies is what separates juniors from seniors. If you are unfamiliar with testing React applications, you can find and study a ton of materials about it.



Perhaps you've written a few unit tests at some point, but your experience isn't enough to create integration tests that span the entire application? This shouldn't bother you, as, again, there are countless resources to help you fill knowledge gaps and experience.



For example, here is my article on the full cycle of testing a full stack application based on React.



6. Distinguish between situations in which you should use local and global state



Here we will touch on the topic of managing application state in React. There are tons of technologies to solve this problem. For example, this is redux, mobx, recoil, API, contextand much more. It is not even easy to list them.



But regardless of which state management technology you choose, I often see React juniors get confused when deciding whether to use global or local state. Unfortunately, there are no clear rules for making such decisions unambiguously. But some rules regarding this issue can still be formulated. Namely, in order to decide whether to use the global or local state to store some data, answer the following questions:



  • Do we need some component not directly related to our component to be able to work with its data? For example, the user's name may appear in the navigation bar and on the welcome screen.
  • Should data persist when navigating between application pages?
  • Are many components using the same data?


If these questions can be answered positively, then it might be worth taking advantage of global state. But, I'll tell you right away, you shouldn't store information about what is happening with the menu in the global state. When deciding where to store some data, try to speculate about what data is used in different places in the application, and what data may well be stored only inside the components.



Outcome



Now you know which paths should be taken in order to grow professionally in the field of React development.



When I think back to the code I wrote when I was a React Junior, one thing comes to my mind. I was writing overcomplicated code that was hard to understand. As I gained more experience, I began to notice how my code became simpler. The simpler the code, the better. My code is now easy to understand, and you can understand it even six months after it was written, when it turns out that an error has crept into it that needs to be dealt with.



What paths to professional growth for React programmers do you know?






All Articles