一名 Vue 程序员总结的 React 基础

 一、生命周期

React 生命周期图解[1]

我已经把这张图印在脑子里面了,没事就自己画画,中间发散一些自己的思考。u1s1,不知道 react 的生命周期命名为什么要怎么长~~~, 小程序,vue 的都比较短。毕竟使用的频率还是很高的,Hooks 除外。

公司主营业务:成都做网站、成都网站设计、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。创新互联是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。创新互联推出白云免费做网站回馈大家。

image.png

1、constructor

constructor 是类通用的构造函数,常用于初始化,算是生命周期的一环。React 后来的版本中类组件也可以不写。

注意:在构造函数中使用时,super 关键字将单独出现,并且必须在使用 this 关键字之前使用。super 关键字也可以用来调用父对象上的函数。MDN 说明[2]

 
 
 
 
  1. class JJTest extends React.Component {  
  2.   // constructor 写法  
  3.   constructor(props) {  
  4.     super(props);  
  5.     this.state = {  
  6.       count: 0,  
  7.     };  
  8.     thisthis.handleClick = this.handleClick.bind(this);  
  9.   }  
  10.   // 直接声明  
  11.   state = {  
  12.     count: 0,  
  13.   };  

2、getDerivedStateFromProps

触发时机:state 变化、props 变化、forceUpdate,如上图。

这是一个静态方法, 是一个和组件自身"不相关"的角色. 在这个静态方法中, 除了两个默认的位置参数 nextProps 和 currentState 以外, 你无法访问任何组件上的数据。

 
 
 
 
  1. // 初始化/更新时调用  
  2. static getDerivedStateFromProps(nextProps, currentState) {  
  3.   console.log(nextProps, currentState, "getDerivedStateFromProps方法执行");  
  4.   // 返回值是对currentState进行修改  
  5.   return { 
  6.     fatherText: nextProps.text,  
  7.   };  

3、render

render 函数返回的 JSX 结构,用于描述具体的渲染内容, render 被调用时,它会检查 this.props 和 this.state 的变化并返回以下类型之一:

  •  React 元素。通常通过 JSX 创建。例如,
  •  会被 React 渲染为 DOM 节点, 会被 React 渲染为自定义组件,无论是
  •  还是 均为 React 元素。
  •  数组或 fragments。使得 render 方法可以返回多个元素。欲了解更多详细信息,请参阅 fragments 文档。
  •  Portals。可以渲染子节点到不同的 DOM 子树中。欲了解更多详细信息,请参阅有关 portals 的文档
  •  字符串或数值类型。它们在 DOM 中会被渲染为文本节点
  •  布尔类型或 null。什么都不渲染。(主要用于支持返回 test && 的模式,其中 test 为布尔类型。)

注意:如果 shouldComponentUpdate() 返回 false,则不会调用 render()。

Hooks 不需要写 render 函数。要注意的一点是,即使 Hooks 不需要写 render, 没有用到 React.xxx,组件内还是要import React from "react";的(至于原因,后续深入 Hooks 学一下,大哥们也可以解释下)。React 官方也说了,后续的版本会优化掉这一点。

4、componentDidMount

主要用于组件加载完成时做某些操作,比如发起网络请求或者绑定事件。当做 vue 的 mounted 用就行了,这里需要注意的是:

componentDidMount() 里直接调用 setState()。它将触发额外渲染,也就是两次 render,不过问题不大,主要还是理解。

5、shouldComponentUpdate

该方法通过返回 true 或者 false 来确定是否需要触发新的渲染。因为渲染触发最后一道关卡,所以也是性能优化的必争之地。通过添加判断条件来阻止不必要的渲染。注意:首次渲染或使用 forceUpdate() 时不会调用该方法。

React 官方提供了一个通用的优化方案,也就是 PureComponent。PureComponent 的核心原理就是默认实现了 shouldComponentUpdate 函数,在这个函数中对 props 和 state 进行浅比较,用来判断是否触发更新。

当然 PureComponent 也是有缺点的,使用的时候一定要注意:由于进行的是浅比较,可能由于深层的数据不一致导致而产生错误的否定判断,从而导致页 面得不到更新。不适合使用在含有多层嵌套对象的 state 和 prop 中。

 
 
 
 
  1. shouldComponentUpdate(nextProps, nextState) {  
  2.   // 浅比较仅比较值与引用,并不会对 Object 中的每一项值进行比较  
  3.   if (shadowEqual(nextProps, this.props) || shadowEqual(nextState, this.state) ) {  
  4.     return true  
  5.   }  
  6.   return false  

6、getSnapshotBeforeUpdate

在 DOM 更新前被调用,返回值将作为 componentDidUpdate 的第三个参数。

 
 
 
 
  1. getSnapshotBeforeUpdate(prevProps, prevState) {  
  2.     console.log("getSnapshotBeforeUpdate方法执行");  
  3.     return "componentDidUpdated的第三个参数";  

7、componentDidUpdate

首次渲染不会执行此方法。可以使用 setState,会触发重渲染,但一定要小心使用,避免死循环

 
 
 
 
  1. componentDidUpdate(preProps, preState, valueFromSnapshot) {  
  2.    console.log("componentDidUpdate方法执行");  
  3.    console.log("从 getSnapshotBeforeUpdate 获取到的值是", valueFromSnapshot);  
  4.  } 

8、componentWillUnmount

主要用于一些事件的解绑,资源清理等,比如取消定时器,取消订阅事件

小结

生命周期一定要好好理解,一定要动手写,看一下每种情况下,生命周期的执行结果。上述代码中在React-TypeScript 仓库[3]中都有,可以 clone 下来跑跑看,或者直接访问俊劫学习系统 LifeCycle[4]。还有些其他的生命周期,componentDidCatch, UNSAFE_componentWillMount()等等,简单了解下就行。

二、JSX

1、循环列表

jsx 中一般用 map 来渲染列表循环类的,vue 中直接在 template 中写 v-for 即可

 
 
 
 
  1. {  
  2.   list.map((item, index) => {  
  3.     return ;  
  4.   });  

2、样式

(1)className

单独写一个 class 是可以的,动态拼接需要借助 classnames[5] 库

 
 
 
 
  1. import style from './style.css'  
  2.  

(2)style

需要注意的:两个括号(样式被当做一个对象来解析),类似-连接的样式属性需要转换成小驼峰写法。

 
 
 
 
  1. 样式
 

(3)css 隔离

u1s1,css 隔离这块还是 vue 的 scoped 好用

create-react-app 中内置了使用 CSS Modules 的配置,和 vue 的 scoped 原理相似,都是在生成的 class 后面加了 hash 值

 
 
 
 
  1. // style.module.css  
  2. .text {  
  3.     color: blue  
  4. }  
  5. // app.tsx  
  6. import s from "./style.module.css";  
  7. class App extends Component { 
  8.    render() {  
  9.     return css-module text
;  
  •   }  
  • }  
  • // 编译后  
  • .text_3FI3s6uz {  
  •     color: blue;  
  • 目前社区里最受欢迎的一款 CSS in JS 方案,个人感觉有点别扭,不太喜欢

     
     
     
     
    1. //引入styled-components  
    2. import styled from "styled-components";  
    3. //修改了div的样式  
    4. const Title = styled.div`  
    5.   font-size: 30px;  
    6.   color: red;  
    7. `;  
    8. class App extends Component { 
    9.   render() {  
    10.     return (  
    11.       <>  
    12.         CSS in JS 方案  
    13.         
    14.     );  
    15.   }  

    3、一个 JSX

    刚开始从 vue 转过来会有些不适应(话说有多少人直接在 vue 里面写 JSX 的),之前用的都是 Vue Sfc 写法,当然多写写就熟悉了。至于 React 采用 JSX 的优劣势,评论区各抒己见哈。

    代码对应页面预览[6]

    image.png

     
     
     
     
    1. render() {  
    2.     return (  
    3.       <>  
    4.           
    5.           
    6.             
    7.             修改父组件文本内容  
    8.             
    9.             
    10.             {this.state.hideChild ? "显示" : "隐藏"}子组件  
    11.             
    12.           {this.state.hideChild ? null : (  
    13.               
    14.           )}  
    15.         
      
  •         
      
  •             
  •           
  •             src={this.state.lifeCycle}  
  •             title="navigation"  
  •             width="100%"  
  •             height="600px"  
  •             onLoad={this.onLoading}  
  •             onError={this.onLoading}  
  •           >  
  •           
  •         
  •     );  
  •   } 
  • 三、基础组件

    组件这块,个人感觉和 vue 差别还是比较大的,颗粒度更细致,当然也增加了一定难度。这里就简单例举一个TS版本的,带 Icon 的标题组件

     
     
     
     
    1. import cn from "classnames";  
    2. import React from "react";  
    3. import "./style/index.less";  
    4. import { Icon,IIconProps } from "zent";  
    5. interface IProps {  
    6.   title: string;  
    7.   iconType?: IIconProps['type'];  
    8.   isShowIcon?: boolean;  
    9.   iconClassName?: string;  
    10.   titleClassName?: string; 
    11.  }  
    12. export const ContentTitle: React.FC = (props) => {  
    13.   const { title, iconType = 'youzan', isShowIcon = false , iconClassName, titleClassName, ...popProps } = props; 
    14.   return (  
    15.       
    16.       {title}  
    17.       {isShowIcon && 
    18.         className={cn("content-title__icon", iconClassName)}  
    19.         {...popProps} 
    20.         type={iconType}  
    21.       />}  
    22.       
    23.   );  
    24. };  
    25. export default ContentTitle; 

    四、高阶组件 HOC

    1、含义

    和 vue mixins 相同,都是为了解决代码复用的问题,但 react 中已经废弃 mixins,vue 中也不推荐使用。主要是会带来命名冲突,相互依赖,不方便维护等一些缺点。

    高阶组件其实就是处理 react 组件的函数,简单理解就是和 ES6 中提供的 export/import 作用相似,不同点在于:高阶组件会进行加工后再导出你需要的东西。类似于方程式:y = ax + b, x 是入口(组件),会根据 a 和 b 进行计算,得到最终的 y(处理后的组件) 给到你用。

    2、Demo

    官网的实现 Demo: 高阶组件[7]

    一个简单的高阶组件(实现有两种方式:属性代理和反向继承):

     
     
     
     
    1. // 属性代理: 组件属性的一些修改  
    2. const JJHOC = (WrappedComponent) => {  
    3.   return class NewComponent extends React.Component {  
    4.     render() {  
    5.       const newProps = { type: "HOC" };  
    6.       return ;  
    7.     }  
    8.   };  
    9. }; 
    10.  // 反向继承: 在render() 方法中返回 super.render() 方法  
    11. const JJHOC = (WrappedComponent) => {  
    12.   return class NewComponent extends WrappedComponent {  
    13.     render() {  
    14.       return super.render();  
    15.     }  
    16.   };  
    17. }; 

    3、常用 HOC

    五、组件通信

    1、props

    和 vue 不同的是,react props 传值可以直接写,不需要声明。在 props 上挂载 function,就相当于是 vue 的$emit。同样需要注意的是子组件不可以修改 props 的值

     
     
     
     
    1. import React from "react";  
    2. function Child(props) {  
    3.   const sendMsg = (msg) => {  
    4.     props.onClick("子组件的消息");  
    5.   };  
    6.   return (  
    7.     
       
    8.        
      子组件标题:{props.title}
        
    9.        sendMsg("子组件消息")}> 子传父   
    10.       
    11.   );  
    12. }  
    13. function Father() { 
    14.   const onClick = (msg) => { 
    15.     console.log(`父组件接收:${msg}`);  
    16.   };  
    17.   return (  
    18.     
        
    19.         
    20.       
    21.   );  
    22. }  
    23. export default Father; 

    2、context

    React Context 官网说明[8],跨组件传值。创建了一个上下文,同 context 内的组件都可以 通过 Provider 配合 value 使用数据

     
     
     
     
    1. import * as React from "react";  
    2. import { Button } from "zent";  
    3. // Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。  
    4. // 为当前的 theme 创建一个 context(“primary”为默认值)。  
    5. const ThemeContext = React.createContext("primary");  
    6. export default class App extends React.Component {  
    7.   render() { 
    8.     // 使用一个 Provider 来将当前的 theme 传递给以下的组件树。  
    9.     // 无论多深,任何组件都能读取这个值。  
    10.     // 在这个例子中,我们将 danger 作为当前的值传递下去。  
    11.     return (  
    12.         
    13.           
    14.         
    15.     );  
    16.   }  
    17. }  
    18. // 中间的组件再也不必指明往下传递 theme 了。  
    19. function Toolbar() {  
    20.   return (  
    21.     
        
    22.         
    23.       
    24.   );  
    25. }  
    26. class ThemedButton extends React.Component {  
    27.   // 指定 contextType 读取当前的 theme context。  
    28.   // React 会往上找到最近的 theme Provider,然后使用它的值。  
    29.   // 在这个例子中,当前的 theme 值为 “danger”。  
    30.   static contextType = ThemeContext;  
    31.   render() {  
    32.     return context测试;  
    33.   }  

    3、Redux

    Redux 中文文档[9]

    redux 的三大核心:

    不一定非要用,很多项目 context 就已经够用了

    (1)挂载

    使用 createStore 创建一个 store 并通过 Provider 把它放到容器组件中

     
     
     
     
    1. // index.js  
    2. const store = createStore(appReducer);  
    3. ReactDOM.render(  
    4.     
    5.       
    6.   ,  
    7.   document.getElementById("root"); 
    8. ); 

    (2)创建修改的方法

    和 vuex 相似,都是通过 action 来修改数据

     
     
     
     
    1. // action.js  
    2. export const addConst = (payload) => {  
    3.   type: "ADD_CONST",  
    4. }  
    5. export const minusConst = (payload) => {  
    6.  type: "MINUS_CONST",  

    (3)创建一个 store 集合

    当 dispatch 触发相应的方法,执行对应的操作,修改 store 数据。

     
     
     
     
    1. // appReducer.js  
    2. const initialState = { count: 0 };  
    3. const reducer = (state = initialState, action) => {  
    4.   switch (action.type) { 
    5.     case "ADD_CONST":  
    6.       return { count: count + 1 };  
    7.     case "MINUS_CONST":  
    8.       return { count: count - 1 };  
    9.     default:  
    10.       return state;  
    11.   }  
    12. }; 
    13. export default reducer; 

    (4)组件中 redux 使用姿势

     
     
     
     
    1. import React from "react";  
    2. import { connect } from "react-redux";  
    3. const ReduxDemo: React.FC = (props) => {  
    4.   const addCount = () => {  
    5.     const { dispatch } = props;  
    6.     dispatch({ 
    7.        type: "ADD_CONST", 
    8.     });  
    9.   };  
    10.   const minusCount = () => {  
    11.     const { dispatch } = props;  
    12.     dispatch({  
    13.       type: "MINUS_CONST",  
    14.     });  
    15.   };  
    16.   return (  
    17.     
        
    18.       加  
    19.       减  
    20.       
      {props.state}
        
    21.       
    22.   );  
    23. };  
    24. const mapStateToProps = (state) => {  
    25.   return {  
    26.     count: state.count,  
    27.   };  
    28. };  
    29. export default connect(mapStateToProps)(ReduxDemo); 

    六、组件校验

    React 官网 使用 PropTypes 进行类型检查[10] react props 不是必须声明的,但是如果项目规范起来,就需要在 propTypes 中声明 props 类型,注意需要引入prop-types库

    不过现在更多的是通过 typescript 来校验类型了,开发阶段就能发现问题。

     
     
     
     
    1. import * as React from "react";  
    2. import PropTypes from "prop-types";  
    3. interface IProps {  
    4.   name: string;  
    5. }  
    6. const PropsDemo: React.FC = ({ name }) => {  
    7.   return 

      Hello, {name}

      ;  
    8. };  
    9. PropsDemo.propTypes = {  
    10.   name: PropTypes.string,  
    11. }; 

    七、React Router

    1、注意

    2、一个 Demo 

     
     
     
     
    1. import React, { Component } from "react";  
    2. import Admin from "./pages/admin/admin";  
    3. import Login from "./pages/login/Login";  
    4. import { HashRouter, Route, Switch } from "react-router-dom";  
    5. class App extends Component {  
    6.   render() {  
    7.     return (  
    8.         
    9.           
    10.             
    11.             
    12.           
    13.         
    14.     );  
    15.   }  
    16. }  
    17. export default App; 

    3、路由传参

    (1)params

     
     
     
     
    1. // router  
    2.   
    3. // 传参  
    4. xxx  
    5. this.props.history.push({pathname:`/path/${id}`});  
    6. // 获取  
    7. this.props.match.params.id 

    (2)query

     
     
     
     
    1. // router  
    2.   
    3. // 传参  
    4. xxx  
    5. this.props.history.push({pathname:"/query",query: { id : '789' }});  
    6. // 获取  
    7. this.props.location.query.id 

    (3)Hooks

     
     
     
     
    1. // 跳转  
    2. let history = useHistory();  
    3. history.push("/");  
    4. // 获取  
    5. useLocation();  
    6. useParams();  
    7. useRouteMatch(); 

    4、exact 属性

    exact 是 Route 下的一条属性,一般而言,react 路由会匹配所有匹配到的路由组价,exact 能够使得路由的匹配更严格一些。

    exact 的值为 bool 型,为 true 是表示严格匹配,为 false 时为正常匹配。

    如在 exact 为 true 时,’/link’与’/’是不匹配的,但是在 false 的情况下它们又是匹配的。

    八、总结

    学完生命周期,多练习 JSX,配合 React Router 和 Redux 多写写组件,基本就能上手开发了。没有过多的 API 需要学习,写起来也比较自由。React 虽然生态强大,选着性比较多,但是这样产生了一个问题:什么是 React 的最佳实践?

    新闻名称:一名 Vue 程序员总结的 React 基础
    URL分享:http://www.shufengxianlan.com/qtweb/news28/548728.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

    猜你还喜欢下面的内容

    网站建设知识

    同城分类信息