React组件设计模式与最佳实践

React设计思想

U I = f ( d a t a ) X UI = f(data)X UI=f(data)X

  1. 在React中,界面完全由数据驱动
  2. 在React中,一切都是组件
    • 用户界面就是组件
    export default function Button {}
    
    • 组件可以嵌套包装,组成复杂功能
    • 组件可以用来实现副作用(ajax、修改dom、埋点等)
  3. props是组件间通讯的基本方式,还有context,redux,event bus等

定义清晰可维护的接口

设计原则

  • 保持接口小,props属性少

  • 合理拆分组件,根据数据边界划分组件,充分组合

  • 把state往上层组件提取,让下层组件只需要实现为纯函数

  • 保持小的更新,细粒度且合理拆分组件,react的diff比对是以组件为单位进行的

最佳实践
  • 避免render函数,访问同样的props和state,代码依然耦合在一起
  • 命名:给回调类型的函数加统一前缀 on开头 (onStart, onSubmit)
  • 对参数定义类型约束
import PropTypes from 'prop-types'
const ControlButton=(props)=>{
    //todo
}
ControlButton.propTypes={
    height: PropTypes.number,
    content: PropTypes.string.isRequired 
}

组件内部实现

功能正常、代码整洁、高性能

1. 组件代码拆分

每个组件都有自己专属的代码文件

const BaseInfo = (props) => {
};

export default BaseInfo;

代码整洁,易维护,组件互不影响

2. 用解构赋值获取props的属性
const BaseInfo = ({activated, onStart, onPause, onReset, onSplit}) => {

}

简化代码,参数一目了然,默认值

3. class组件,利用属性初始化定义state和成员函数
class SellInfo extends React.Component {
  //this.state, this.onClick=this.onClick.bind(this)
  state = {
    isStarted: false,
  }
  onClick = () => {
    this.setState({
      isStarted: true,
    });
  }
}

好看且性能好,保留this

组件设计模式

  • 傻瓜组件和聪明组件
  • hoc模式
  • render props模式
  • 提供者模式
  • 组合模式

1. 聪明组件和傻瓜组件

  • 别名:

    • 有状态组件和无状态组件
    • 容器组件和渲染组件
  • 优点

    • 责任分离, 聪明组件负责管理数据状态,傻瓜组件负责展示数据
    • 如果要优化界面,只需要去修改傻瓜组件,如果想改进数据管理和获取,修改聪明组件
2. 聪明组件和傻瓜组件:提升性能
  • class: PureComponent,实现shouldComponentUpdate浅比较

  • hoc:React.memo

  • hooks: useMemo, useCallback

2.1 React.memo
  • 默认情况浅层比较,传入第二个参数,可自定义深层比较
function MyComponent(props) {
  /* render using props */
}
function areEqual(prevProps, nextProps) {
  /*
  return true if passing nextProps to render would return
  the same result as passing prevProps to render,
  otherwise return false
  */
}
export default React.memo(MyComponent, areEqual);
2.2 useMemo
  • 第二个参数为依赖项,执行回调函数
export default (props = {}) => {
    console.log(`--- component re-render ---`);
    return useMemo(() => {
        console.log(`--- useMemo re-render ---`);
        return <div>
            {/* <p>step is : {props.step}</p> */}
            {/* <p>count is : {props.count}</p> */}
            <p>number is : {props.number}</p>
        </div>
    }, [props.number]);
}
2.3 useCallback
  • useCallback 缓存钩子函数,useMemo 缓存返回值
const isEvenNumber = useMemo(() => {
    return count % 2 === 0;
  }, [count]);

  const onClick = useCallback(() => {
    setCount(count + 1);
  }, [count]);
   return (
    <div>
      <div>{count} is {isEvenNumber ? 'even':'odd'} number</div>
      <button onClick={onClick}></button>
    </div>
  );

3. hoc模式

const OrderList = () => {
  if (getUserId()) {
    return ...; // 显示订单列表
  } else {
    return null;
  }
};
const ProductList = () => {
  if (getUserId()) {
    return ...; // 显示商品列表
  } else {
    return null;
  }
};
3.1 hoc模式:抽取共同逻辑,强化组件
const withAuth = (Component) => {
  //强化操作
  const NewComponent = (props) => {
    if (getUserId()) {
      return <Component {...props} />;
    } else {
      return null;
    }
  }
  return NewComponent;
};
const OrderList = withAuth((props) => {
  return ...; // 显示订单列表
});
3.1 hoc特点
  • 高阶组件是一个纯函数,传入组件,返回一个新的组件,包含参数组件。
  • 高阶组件不能去修改作为参数的组件,一般把传给自己的 props 转手传递给作为参数的组件
  • 命名一般以with开头
  • 使用场景
    • 权限控制,统一对页面进行权限判断,按不同条件渲染不同内容
    • 代码复用,可以将重复的逻辑进行抽象
3.2 hoc优缺点
  • 优点
    • 抽离和复用逻辑
    • 条件渲染,控制渲染等
  • 缺点
    • 组件多层嵌套, 增加复杂度与理解成本,相同命名的props会覆盖老属性,不清楚props来源
    //假如this.props中含有name 
    const newProps = {name: "cqm",value: "testData"}
    return <ComponentClass {...this.props} {...newProps} />
    

4. render props 模式

  • props作为函数的参数来渲染部分页面
const RenderAll = (props) => {
  return(
     <React.Fragment>
      {props.children(props)}
     </React.Fragment>
  );
};
<RenderAll>
    () => <h1>hello world</h1>}
</RenderAll>
4.1 传递props
const Login = (props) => {
  const userName = getUserInfo();

  if (userName) {
    const allProps = {userName, ...props};
    return {props.children(allProps)};
  } else {
    return null;
  }
};

<Login>
  {({userInfo}) => <h1>Hello {userName}</h1>}
</Login>
4.2 不局限于children
const Auth= (props) => {
  const userName = getUserName();

  if (userName) {
    const allProps = {userName, ...props};
    return {props.login(allProps)};
  } else {
    retrun {props.nologin(props)}
  }
};
<Auth
    login={({userName}) => <h1>Hello {userName}</h1>}
    nologin={() => <h1>Please login</h1>}
/Auth>
4.3 依赖注入
  • 逻辑A依赖于逻辑B和C(A->B、A->C )。依赖注入就是把 B 的逻辑以函数形式传递给 A,A 和 B 达成函数接口一直,逻辑C也可以重用逻辑 A。
  • Login 和 Auth相当于逻辑 A,而传递给组件的函数类型 props,就是逻辑 B 和 C
4.4 和高阶组件的比较
  • props命名可修改,不存在相互覆盖
  • 清楚props来源
  • 比高阶组件更加灵活和简单
  • 不会出现组件多层嵌套,但存在函数回调形式的多层嵌套

5. 提供者模式

场景:假如组件A和组件X之间隔着多层组件,需要传递数据,一层一层传递太麻烦,对于这种跨组件的数据传递,需要提供者模式

5.1 Provider
  • Provider 用于提供 context
//创建context
const ThemeContext = React.createContext();
//提供者
function ThemeProvider(){
    const theme = { color:'pink' }
    return <ThemeContext.Provider value={ theme } >
        <Index />
    </ThemeContext.Provider>
}

5.2 Consumer
  • Consumer 用于消费 context ,render children 函数中第一个参数就是保存的 context
function ThemeConsumer(props){
    return <ThemeContext.Consumer>
      { (theme)=>{ /* render children函数 */
          const { color } = theme
          return <p style={{color }}>
           {props.children}
       </p>
      } }
    </ThemeContext.Consumer>
}
5.2 提供者模式原理
  • 通过 Consumer 订阅 context 变化,context 改变,订阅者状态更新
  • 使用场景:全局传递状态、保存状态、外层组件项内层组件传值。

6. 组合模式

  • 组合模式适合一些容器组件场景,通过外层组件包裹内层组件

  • 这种方式在 Vue 中称为 slot 插槽,外层组件可以轻松的获取内层组件的 props 状态,还可以控制内层组件的渲染,

  • 组合模式能够直观反映出 父 -> 子组件的包含关系

6.1 组合模式实例
  <Tabs onChange={ (type)=> console.log(type)  } >
      <TabItem name="react"  label="react" >React</TabItem>
      <TabItem name="vue" label="vue" >Vue</TabItem>
      <TabItem name="angular" label="angular"  >Angular</TabItem>
  </Tabs>
  • Tabs 负责展示和控制对应的 TabItem 。绑定切换 tab 回调方法 onChange。当 tab 切换的时候,执行回调。

  • TabItem 负责展示对应的 tab 项,向 Tabs 传递 props 相关信息。

6.2 组合模式的原理
  • 在容器组件中通过props.children获取子组件的children,做进一步处理

  • 可以对子组件做类型判断、容器的props混入子组件、子组件传入props的判断控制渲染

  • 既然可以混入容器组件的props,进而可以传递方法参数组件通信

点击加入群聊【小程序/前端交流】,一起学习交流:663077768

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: React教程PDF是一种电子书,用于学习和了解React框架的使用和开发。这个教程通常包含基本概念、核心概念、组件、状态管理、路由等内容。 在这个教程中,你可以学习到如何使用React构建UI组件React的虚拟DOM概念以及其在性能优化方面的作用。此外,还会介绍React的生命周期方法,这在处理组件的加载、渲染和更新过程中很有用。 除了React基本知识外,教程还可能包含一些实际应用方面的案例和实践经验。这些案例可以帮助你更好地理解React的使用,并提供一些编程技巧和最佳实践。 通常,React教程PDF是免费提供的,你可以从官方网站、开源社区或一些教育平台上找到这些资源。当然,有时也会出现一些收费的高质量教程,这些教程会提供更深入和全面的内容。 无论你是React初学者还是有一些经验的开发者,通过阅读React教程PDF可以帮助你扩展知识和提升技能,进一步了解React框架。最重要的是,你可以通过教程中提供的实例和指导来实践和运用你的学习成果,以便更好地应用React在真实项目中。 ### 回答2: React 是一个用于构建用户界面的 JavaScript 库,它可以帮助开发者创建高效、可重用的组件化界面。如果你想学习 React,最好的方式是通过官方提供的教程。 React 的官方网站提供了一个详尽的教程,其中包含了许多实用的示例和解释。这个教程是免费提供的,并且可以在网站上直接阅读或者下载为 PDF 格式。它的内容非常全面,适合初学者入门以及有一定经验的开发者用作参考。 在这个教程中,你将学习到 React 的基本概念,包括组件、状态和属性等。你将了解到如何创建组件、处理事件、进行条件渲染等等。教程还会引导你使用 JSX 语法编写代码,这是 React 的核心特性之一,可以让你在 JavaScript 中嵌入 XML 标记,更加直观地描述界面结构。 此外,教程还会介绍如何使用 React 的生态系统,比如 React Router 进行路由管理,以及 Redux 进行状态管理。你将了解到如何使用 Babel 和 Webpack 进行工程化的配置,以及如何使用 React 开发工具进行调试。 总的来说,React 的官方教程提供了非常丰富的内容,无论你是初学者还是有一定经验的开发者,都能从中获得很多收益。如果你想深入学习 React,我强烈推荐你阅读这个教程。你可以访问 React 官方网站并下载相应的 PDF 版本。祝你学习愉快! ### 回答3: React 是一个用于构建用户界面的 JavaScript 库。它提供了高效的设计和开发工具,使得前端开发变得更加简单和快捷。React 使用虚拟 DOM 的概念,将页面的更改抽象为不同的状态,在状态变化时只需要更新需要修改的部分,而不是整个页面,从而提高了性能。 React 的教程主要介绍了 React 的基本概念和用法。它从环境搭建开始,讲解了如何使用 React 的各个部分,包括组件、props、状态管理等。教程提供了一些示例代码,并对其进行了详细解释,让读者能够快速入门并理解 React 的基本原理。 React 教程的优点之一是它的实用性。通过教程,读者可以学习到如何通过 React 构建复杂的用户界面,并了解到一些常用的设计模式最佳实践。教程还提供了一些实例项目,帮助读者将所学应用到实际项目中。 此外,教程还介绍了一些与 React 相关的工具和库,如 React Router 和 Redux。这些工具可以帮助开发者更好地组织和管理 React 项目,提高开发效率。 总的来说,React 教程是一个很好的入门资源,它能够帮助读者快速掌握 React 的基本概念和用法,并提供了一些实用的示例和项目,让读者能够在实际开发中更好地应用 React。无论是刚入门的前端开发者还是有一定经验的开发者,都可以从中获得很多有益的知识和经验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kiki·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值