前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React 设计模式 0x1:组件

React 设计模式 0x1:组件

作者头像
Cellinlab
发布2023-05-17 21:06:05
8400
发布2023-05-17 21:06:05
举报
文章被收录于专栏:Cellinlab's BlogCellinlab's Blog

学习如何轻松构建可伸缩的 React 应用程序:编写组件

# 命名规范

编程中常见的命名方式有:

驼峰式命名法(Camel Case),也叫小驼峰式命名法(Lower Camel Case)

代码语言:javascript
复制
const camelCase = "camelCase";

帕斯卡命名法(Pascal Case),也叫大驼峰式命名法(Upper Camel Case)

代码语言:javascript
复制
const PascalCase = "PascalCase";

在 React 中,组件的命名方式是大驼峰式命名法,即组件的名称必须以大写字母开头。

代码语言:javascript
复制
import React from "react";

const MyComponent = () => {
  return <div>My Component</div>;
};

export default MyComponent;

# 函数式组件

函数组件是普通的 JavaScript 函数,它接收 props 作为输入并返回一个 React 组件。

可以是一个箭头函数:

代码语言:javascript
复制
import React from "react";

const MyComponent = (props) => {
  return <div>My Component</div>;
};

export default MyComponent;

或普通函数:

代码语言:javascript
复制
import React from "react";

function MyComponent(props) {
  return <div>My Component</div>;
}

export default MyComponent;

函数组件具有一些常见的 hook 。React hooks 使得大多数开发人员能够构建可伸缩的 React 应用程序。

# useState

useState 是 React 中最常用的 hook 之一,它用于在函数式组件中存储状态值(对象、字符串、布尔值等),这些值在组件的生命周期中进行变更。useState 接受一个初始值,如果是字符串则可以为空字符串,这个值可以在组件的生命周期中进行更新。

代码语言:javascript
复制
import React, { useState } from "react";

const MyComponent = () => {
  const [name, setName] = useState("");

  return (
    <div>
      <h1>My Component</h1>
      <input type="text" value={name} onChange={(e) => setName(e.target.value)} />
    </div>
  );
};

export default MyComponent;

# useRef

useRef 方法也是大多数函数组件中常用的 React hooks 之一。useRef 方法常用于指向 DOM 中的一个元素,可用于创建不受控制的元素。

代码语言:javascript
复制
import React, { useRef } from "react";

const MyComponent = () => {
  const inputRef = useRef(null);

  const browseFile = () => {
    if (inputRef.current) {
      inputRef.current.click();
    }
  };

  return (
    <div>
      <input type="file" ref={inputRef} />
      <button onClick={browseFile}>Browse File</button>
    </div>
  );
};

export default MyComponent;

# useEffect

useEffect 方法也是大多数功能组件中常用的 React hook 。useEffect 方法是一种异步钩子,让我们可以在组件上执行异步任务,这些异步任务包括调用 API 并通过 useState 保存数据。

useEffect 接受两个参数,分别是:

  • 带有可选的返回语句的函数
    • 可选的返回语句是一个函数,它在组件卸载时执行,用于进行清理工作,如定时器、事件监听器等
  • 可选的依赖项数组
    • 当不传入依赖项数组时,useEffect 会在每次渲染时执行
    • 当传入依赖项数组时
      • 如果数组为空,则 useEffect 只会在组件挂载时执行
      • 如果数组不为空,则 useEffect 会在组件挂载时执行,以及当数组中的任何值发生变化时执行
代码语言:javascript
复制
import React, { useState, useEffect } from "react";

const MyComponent = () => {
  const [name, setName] = useState("");
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("render component");
  });

  useEffect(() => {
    console.log("componentDidMount");
    return () => {
      console.log("componentWillUnmount");
    };
  }, []);

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

  return (
    <div>
      <h1>My Component</h1>
      <input type="text" value={name} onChange={(e) => setName(e.target.value)} />
      <button onClick={() => setCount(count + 1)}>Click Me</button>
    </div>
  );
};

export default MyComponent;

# 类组件

类组件是继承自 React.component 的子类组件,这个类组件接受 props 并渲染它们,它以一个 constructor 开始,这个 constructor 会被超类调用。

代码语言:javascript
复制
import React from "react";

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return <div>My Component</div>;
  }
}

export default MyComponent;

类组件有一些常见的生命周期方法:

  • componentDidMount
  • componentDidUpdate

# componentDidMount

该生命周期方法在 React 组件生命周期的挂载阶段被调用,这个方法可以帮助我们在向用户展示数据之前修改 React 组件的内容。

代码语言:javascript
复制
import React from "react";

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "",
    };
  }

  componentDidMount() {
    this.setState({ name: "Cell" });
  }

  render() {
    return <div>My name is {this.state.name}</div>;
  }
}

export default MyComponent;

# componentDidUpdate

该生命周期方法在组件更新后被调用:

代码语言:javascript
复制
import React from "react";

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "",
    };
  }

  componentDidMount() {
    this.setState({ name: "Cell" });
  }

  componentDidUpdate() {
    console.log("componentDidUpdate");
  }

  render() {
    return <div>My name is {this.state.name}</div>;
  }
}

export default MyComponent;

# 组件结构最佳实践

React 组件是构建小型到强大应用程序的方式。这些 React 组件需要以良好的方式进行结构化,以便于进行测试、扩展和易于发现错误。

以下是保持良好的 React 组件结构的最佳方法:

  • 避免使用大型组件
    • 大型组件通常很难阅读、理解和调试
    • 即使应用程序正常运行,当出现问题时,如何调试也将是个问题
    • 应该将大型组件分解为较小的组件,以便于阅读、测试和轻松识别错误
  • 给组件和变量合适的命名
    • 编写合理的变量名、方法名或组件名非常重要
    • 避免使用模糊不清的命名
  • 保持文件夹结构精确和易于理解
    • 文件和文件夹结构在实现良好的组件结构方面也非常重要
    • 为项目提供文件夹结构,以便于理解应该将哪些文件放入特定文件夹中
  • 将可重用的逻辑移至单独的类或函数中
    • 通常在编程中,始终记住 DRY 原则
    • 无论您觉得应用程序或组件将使用哪些可重用的逻辑,都将其移至函数或方法中,并在应用程序中调用
  • 尝试编写测试
    • 测试可以确保您的组件按预期工作,并在编写得当时减少应用程序中的错误数量

# 组件数据共享

在 React 中,一定会在在组件之间共享数据,具体实现方式取决于状态变化的复杂程度和应用程序的大小。

以下是一些实现方式:

  • Props
  • Context API
  • Redux
  • useReducer

# Props

Props 是在 React 中从一个组件传递数据到另一个组件的一种方式,props 是从父组件传递到子组件的对象。Propsproperties(属性)的缩写。

代码语言:javascript
复制
import React from "react";

const MyComponent = (props) => {
  const { name, age } = props;

  return (
    <div>
      <p>My name is {name}</p>
      <p>My age is {age}</p>
    </div>
  );
};

const App = () => {
  return <MyComponent name="Cell" age={18} />;
};

export default App;

# Context API

Context API 也是一种从一个组件传递数据到另一个组件的方式。与 Props 的主要区别在于,Context API 不会在每个组件上从父组件传递到子组件。

Context API 有两个主要方法:

  • Provider
    • Provider 接受一个要传递给子组件的值
  • Consumer
    • Consumer 允许调用组件订阅 context 更新
代码语言:javascript
复制
import React from "react";

const MyContext = React.createContext();

const MyComponent = () => {
  return (
    <MyContext.Consumer>
      {(data) => (
        <div>
          <p>My name is {data.name}</p>
          <p>My age is {data.age}</p>
        </div>
      )}
    </MyContext.Consumer>
  );
};

const MyComponent2 = () => {
  const data = React.useContext(MyContext);

  return (
    <div>
      <p>My name is {data.name}</p>
      <p>My age is {data.age}</p>
    </div>
  );
};

const App = () => {
  return (
    <MyContext.Provider value={{ name: "Cell", age: 18 }}>
      <MyComponent />
      <MyComponent2 />
    </MyContext.Provider>
  );
};

export default App;

# Redux

Redux 是一个开源的 JavaScript 库,它保持全局状态以使应用程序具有一致的行为。

Redux 库包括以下三个部分:

  • Store
    • 用于存储全局状态
    • 这一部分是不可变的,即它无法改变
  • Reducer
    • Reducer 是一个纯函数,它接受两个参数(初始状态和操作),并返回一个新的状态
  • Actions
    • Action 是一个 JavaScript 对象,告诉 Reducer 用户希望在 Store 中执行什么操作
    • Action 是用户的指令,用于在 Store 中要么更改状态,要么创建状态的副本
代码语言:javascript
复制
import { createStore } from "redux";

const initialState = {
  name: "",
  age: 0,
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case "SET_NAME":
      return {
        ...state,
        name: action.payload,
      };
    case "SET_AGE":
      return {
        ...state,
        age: action.payload,
      };
    default:
      return state;
  }
};

const store = createStore(reducer);

store.subscribe(() => {
  console.log(store.getState());
});

store.dispatch({ type: "SET_NAME", payload: "Cell" });
// { name: "Cell", age: 0 }
store.dispatch({ type: "SET_AGE", payload: 18 });
// { name: "Cell", age: 18 }

# useReducer

useReducer 方法也是在组件之间共享数据的一种方式。当您需要进行复杂状态更改时,可以使用 useReducer 方法。

useReducer 方法接受参数为初始状态和操作,返回当前状态和 dispatch 方法。

代码语言:javascript
复制
import { useReducer } from "react";

const initialState = {
  name: "",
  age: 0,
};

const reducer = (state, action) => {
  switch (action.type) {
    case "SET_NAME":
      return {
        ...state,
        name: action.payload,
      };
    case "SET_AGE":
      return {
        ...state,
        age: action.payload,
      };
    default:
      return state;
  }
};

const App = () => {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>My name is {state.name}</p>
      <p>My age is {state.age}</p>
      <button onClick={() => dispatch({ type: "SET_NAME", payload: "Cell" })}>Set Name</button>
      <button onClick={() => dispatch({ type: "SET_AGE", payload: 18 })}>Set Age</button>
    </div>
  );
};

export default App;

# 受控组件 vs 非受控组件

受控组件数据是由 React 组件管理的,而非受控组件数据是由 浏览器或 DOM 处理。受控组件通常由用户输入或事件处理。

代码语言:javascript
复制
import React, { useState, useRef } from "react";

const controlledComponent = () => {
  const [name, setName] = useState("");
  const [age, setAge] = useState(0);

  return (
    <div>
      <input type="text" value={name} onChange={(e) => setName(e.target.value)} />
      <input type="number" value={age} onChange={(e) => setAge(e.target.value)} />
    </div>
  );
};

const uncontrolledComponent = () => {
  const nameRef = useRef();
  const ageRef = useRef();

  const handleSubmit = () => {
    console.log(nameRef.current.value);
    console.log(ageRef.current.value);
  };

  return (
    <div>
      <input type="text" ref={nameRef} />
      <input type="number" ref={ageRef} />
      <button onClick={handleSubmit}>Submit</button>
    </div>
  );
};

const App = () => {
  return (
    <div>
      <controlledComponent />
      <uncontrolledComponent />
    </div>
  );
};

export default App;
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023/2/3,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # 命名规范
  • # 函数式组件
    • # useState
      • # useRef
        • # useEffect
        • # 类组件
          • # componentDidMount
            • # componentDidUpdate
            • # 组件结构最佳实践
            • # 组件数据共享
              • # Props
                • # Context API
                  • # Redux
                    • # useReducer
                    • # 受控组件 vs 非受控组件
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档