開源日報每天推薦一個 GitHub 優質開源項目和一篇精選英文科技或編程文章原文,堅持閱讀《開源日報》,保持每日學習的好習慣。
2024年1月2日,開源日報第1062期:
今日推薦開源項目:《llm-course》
今日推薦英文原文:《Mastering React.js: Best Practices and Design Patterns for High-Quality Applications


開源項目

今日推薦開源項目:《llm-course》傳送門:項目鏈接

推薦理由:這個路線圖和Colab notebooks可以幫助你學習大型語言模型(LLM)相關課程,LLM(大型語言模型)課程分為三個部分:

🧩 LLM基礎知識 包含關於數學、Python 和神經網路的基本知識

🧑‍🔬 LLM科學家 專註於學習如何利用最新技術構建最佳的LLM

👷 LLM工程師 專註於如何創建基於LLM的解決方案並將其部署

Blog 網站直達 https://mlabonne.github.io/blog/


英文原文

今日推薦英文原文:Mastering React.js: Best Practices and Design Patterns for High-Quality Applications

推薦理由:React.js 已成為構建動態用戶界面的首選庫,其基於組件的架構和聲明式語法使其成為創建可擴展且易於維護的應用程序的強大工具,本文概述了最佳實踐和設計模式,如合理項目結構提高可擴展性; 明智使用狀態管理,避免局部狀態傳遞;採用函數組件和Hooks簡化生命周期等等


Mastering React.js: Best Practices and Design Patterns for High-Quality Applications

React.js has become the go-to library for building dynamic user interfaces. Its component-based architecture and declarative syntax make it a powerful tool for creating scalable and maintainable applications. However, as your project grows, maintaining code quality and scalability becomes paramount. In this article, we』ll explore the best practices and design patterns in React.js that will help you build high-quality applications.

1. Project Structure: Organize for Scalability

A well-organized project structure is the foundation for a scalable React application. Consider structuring your project based on features or modules rather than file types. This modular approach makes it easier to locate and update code related to specific functionality.

Example:

/src
  /components
    Header.js
    Footer.js
  /pages
    Home.js
    About.js
  /services
    api.js
  /styles
    main.css
  App.js
  index.js

2. State Management: Use State Wisely

State is at the core of React applications. Effective state management is crucial for building scalable applications. Lift state up to the nearest common ancestor for shared state between components. Utilize state management libraries like Redux for complex state scenarios.

Example:

// Bad: Local state causing prop drilling
import React, { useState } from 'react';

// ChildComponent needs access to count and setCount, so it gets them as props
function ChildComponent({ count, setCount }) {
  return <button onClick={() => setCount(count + 1)}>Increment</button>;
}

// IntermediateComponent receives count and setCount as props but doesn't use them
function IntermediateComponent({ count, setCount }) {
  return (
    <div>
      <p>Intermediate Component</p>
      <ChildComponent count={count} setCount={setCount} />
    </div>
  );
}

// ParentComponent manages the count state and passes it down to IntermediateComponent
function ParentComponent() {
  const [count, setCount] = useState(0);

  return <IntermediateComponent count={count} setCount={setCount} />;
}

// App component renders the ParentComponent
function App() {
  return <ParentComponent />;
}

export default App;
// Good: State lifted up
import React, { useState } from 'react';

// ChildComponent receives count and setCount directly as props
function ChildComponent({ count, setCount }) {
  return <button onClick={() => setCount(count + 1)}>Increment</button>;
}

// ParentComponent manages the count state and passes it down to ChildComponent
function ParentComponent() {
  const [count, setCount] = useState(0);

  return <ChildComponent count={count} setCount={setCount} />;
}

// App component renders the ParentComponent
function App() {
  return <ParentComponent />;
}

export default App;

3. Component Lifecycle: Embrace Functional Components and Hooks

With the introduction of Hooks, functional components have become more powerful than ever. Embrace functional components and use Hooks for state management, side effects, and context. This simplifies code and avoids the complexities of class component lifecycles.

Example:

// Class component with lifecycle methods
class ExampleComponent extends React.Component {
  componentDidMount() {
    console.log('Component did mount');
  }

  componentWillUnmount() {
    console.log('Component will unmount');
  }

  render() {
    return <div>Hello, World!</div>;
  }
}
// Functional component with useEffect Hook
function ExampleComponent() {
  useEffect(() => {
    console.log('Component did mount');
    return () => console.log('Component will unmount');
  }, []);

  return <div>Hello, World!</div>;
}

4. Props: Destructuring and PropTypes

Destructuring props in functional components enhances readability. Additionally, PropTypes offer a way to document and validate component props, preventing common runtime errors.

Example:

// Destructuring props for improved readability
function Greeting({ name, age }) {
  return <div>{`Hello, ${name}! You are ${age} years old.`}</div>;
}
// PropTypes for documenting and validating props
import PropTypes from 'prop-types';

function Greeting({ name, age }) {
  return <div>{`Hello, ${name}! You are ${age} years old.`}</div>;
}

Greeting.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired,
};

5. Reusable Components: Create a Component Library

Encapsulate common UI patterns into reusable components. Building a component library not only accelerates development but also ensures a consistent look and feel throughout your application.

Example:

// Reusable Button component
function Button({ onClick, children }) {
  return <button onClick={onClick}>{children}</button>;
}

6. Error Boundaries: Graceful Handling of Errors

Wrap components with error boundaries to gracefully handle errors and prevent entire UI crashes. This provides a better user experience and facilitates easier debugging.

Example:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, errorInfo) {
    this.setState({ hasError: true });
    // Log error information
    console.error(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return <div>Something went wrong.</div>;
    }

    return this.props.children;
  }
}
import React, { useState } from 'react';

function ErrorBoundary({ children }) {
  const [hasError, setHasError] = useState(false);

  const componentDidCatch = (error, errorInfo) => {
    setHasError(true);
    // Log error information
    console.error(error, errorInfo);
  };

  if (hasError) {
    return <div>Something went wrong.</div>;
  }

  return children;
}

export default ErrorBoundary;

7. Performance Optimization: Memoization and PureComponent

Improve performance by memoizing components using React.memo and utilizing PureComponent for class components. This prevents unnecessary renders and optimizes your application.

Memoized Functional Component:

import React from 'react';

const MemoizedComponent = React.memo(function MyComponent(props) {
  /* render using props */
  console.log('Rendering MemoizedComponent');
  return (
    <div>
      <p>{props.text}</p>
    </div>
  );
});

export default MemoizedComponent;

PureComponent Class Component:

import React from 'react';

class MyPureComponent extends React.PureComponent {
  render() {
    /* render using this.props */
    console.log('Rendering MyPureComponent');
    return (
      <div>
        <p>{this.props.text}</p>
      </div>
    );
  }
}

export default MyPureComponent;

Usage example:

import React, { useState } from 'react';
import MemoizedComponent from './MemoizedComponent';
import MyPureComponent from './MyPureComponent';

function App() {
  const [text, setText] = useState('Initial Text');

  const handleButtonClick = () => {
    setText('Updated Text');
  };

  return (
    <div>
      <button onClick={handleButtonClick}>Update Text</button>
      <MemoizedComponent text={text} />
      <MyPureComponent text={text} />
    </div>
  );
}

export default App;

8. Code Splitting: Optimize Load Time

Break down your application into smaller chunks and load them on demand. Code splitting helps reduce initial load times, making your application more performant.

Example:

// Using React.lazy for code splitting
const MyComponent = React.lazy(() => import('./MyComponent'));

// Suspense for fallback UI while the component is loading
const App = () => (
  <React.Suspense fallback={<div>Loading...</div>}>
    <MyComponent />
  </React.Suspense>
);

9. Testing: Adopt a Robust Testing Strategy

Implement a comprehensive testing strategy using tools like Jest and React Testing Library. Write unit tests, integration tests, and end-to-end tests to ensure the reliability of your application.

Example:

// Jest and React Testing Library test
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';

test('renders component with correct text', () => {
  render(<MyComponent />);
  expect(screen.getByText('Hello, World!')).toBeInTheDocument();
});

10. Accessibility: Prioritize Inclusive Design

Make your application accessible to a wide range of users by following web accessibility standards. Use semantic HTML, provide proper labels, and test your application with screen readers.

Example:

// Using semantic HTML for better accessibility
<button aria-label="Close" onClick={handleClose}>
  <span aria-hidden="true">×</span>
</button>

Conclusion

Building high-quality React applications involves a combination of best practices and design patterns. By adhering to these guidelines, you』ll not only enhance the maintainability and scalability of your project but also contribute to a positive development experience for your team. Keep evolving with the React ecosystem, stay updated on new features, and continuously refine your approach to ensure your applications remain at the forefront of web development.


下載開源日報APP:https://openingsource.org/2579/
加入我們:https://openingsource.org/about/join/
關注我們:https://openingsource.org/about/love/