React 面向组件编程(上)

Posted 清风 与我

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React 面向组件编程(上)相关的知识,希望对你有一定的参考价值。

目录

前言:

在React中,组件实例的三大核心属性包含state、props、ref,通过这三大核心属性的使用,我们能够实现对组件的状态进行更新。


一、组件的基本理解和使用

1. 函数式组件

function MyComponent()
    return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>

ReactDOM.render(<MyComponent />,document.getElementById('test'))

2. 类式组件

class MyComponent extends React.Component
    render()
        return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
    

ReactDOM.render(<MyComponent />,document.getElementById('test'))

3. 注意事项

  1. 组件名必须首字母大写
  2. 虚拟DOM元素只能有一个根元素
  3. 虚拟DOM元素必须有结束标签

4. 渲染函数式组件标签的基本流程

  1. React 解析了组件标签,找到对应的组件
  2. 发现这个组件是一个函数定义的,随后调用该函数,生成了一个虚拟DOM
  3. 最后将虚拟DOM转化为真实DOM,呈现在页面中;

5. 渲染类组件标签的基本流程

  1. React 解析了组件标签,找到对应的组件
  2. 发现这个组件是一个类定义的,随后new出来一个实例对象,并通过该实例调用原型上的render方法
  3. 将render()返回的内容生成了一个虚拟DOM
  4. 最后将虚拟DOM转化为真实DOM,呈现在页面中;

二、组件三大核心属性 1:state

React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。


1. 代码示例

<script type="text/babel">
   // 1. 创建一个类式组件
   class Weather extends React.Component
      // 构造器调用了几次? --- 实例化了几次,调用几次 --- 1次
      constructor()
          super();
          // console.log(this)
          this.state = isHot:false,wind:"微风"

          this.changeWeather = this.changeWeather.bind(this)
      
      // render方法是放在原型上的
      // render中的this是谁? -- 实例对象 <===> Weather组件实例对象
      // render方法调用了几次? --- 1 + N
      // 调用的流程:
          // 1. 页面状态发生改变时,重新调用render方法来生成一个新的虚拟DOM
          // 2. 通过diff算法来 对比 新旧虚拟DOM之间的差别,从而进行合并
          // 3. 将对比合并过后的虚拟DOM 转换为真实DOM,挂载到页面的指定位置
      render()
          // console.log('render中的this',this)
          // onClick事件:首字母需要大写,由于changeWeather是作为onClick的事件回调,所以这里需要一个函数体,而不是函数执行后的结果
          let isHot,wind = this.state
          return <h2 onClick=this.changeWeather>今天的天气很 isHot? '炎热' : '凉爽' wind</h2> // isHot
      
      // changeWeather调用几次?  --- 点几次调用几次
      changeWeather()
          // 因为Babel编译,所以导致类中的方法默认开启局部的严格模式,所以这里的this是undefined
          // console.log('changeWeather',this.state)
          // 严重注意:状态(state)不可直接修改
          // this.state.isHot = !this.state.isHot // 这里是一种错误写法
          let isHot = this.state
          this.setState( isHot:!isHot ) // 这里的修改是一种合并,对比属性的变化,如果有赋新值,如果没有跳过;
      
  
  // 2. 渲染到页面中的指定 DOM
  // ReactDOM.render(虚拟DOM,真实DOM)
  ReactDOM.render(<Weather />,document.getElementById('test'))
</script>

2. 效果展示


3. 注意

  1. 组件中render方法中的this为组件实例对象
  2. 组件自定义的方法中this为undefined,如何解决?
    1. 强制绑定this: 通过函数对象的bind()
    2. 箭头函数
  3. 状态数据,不能直接修改或更新

4. 设置状态:setState

setState(object nextState[, function callback])

不能在组件内部通过 this.state 修改状态,因为该状态会在调用 setState() 后被替换。

setState() 并不会立即改变 this.state,而是创建一个即将处理的 state。setState() 并不一定是同步的,为了提升性能 React 会批量执行 state 和 DOM 渲染。

setState() 总是会触发一次组件重绘,除非在 shouldComponentUpdate() 中实现了一些条件渲染逻辑。


三、 组件三大核心属性 2:props

react 中说的单向数据流值说的就是 props,根据这一特点它还有一个作用:组件之间的通信。props 本身是不可变的,但是有一种情形它貌似可变,即是将父组件的 state 作为子组件的 props,当父组件的 state 改变,子组件的 props 也跟着改变,其实它仍旧遵循了这一定律:props 是不可更改的。


1. 函数式组件代码示例

<script type="text/babel">
    function Person (props) 
        let name,age,sex = props
        return(
            <ul>
                <li>姓名:name</li>
                <li>性别:sex</li>
                <li>年龄:age+1</li>
            </ul>
        )
    

    // 给指定的属性,添加默认值
    Person.defaultProps = 
        sex:'男'
    
    // 1. 数据类型,是否应该有对应的限制?
    // 2. 数据的数量,批量性传输的时候,可以使用展开运算符
    // let speak = 'speak'
    ReactDOM.render(<Person name="tom" age="18" sex="男"/>,document.getElementById('test1'))
    ReactDOM.render(<Person name="jock" age="19" sex="女"/>,document.getElementById('test2'))
    
    const p = name:'老王',age:22
    ReactDOM.render(<Person ...p/>,document.getElementById('test3'))
</script>

2. 类式组件代码示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Props基本使用</title>
</head>
<body>
    <!-- 准备好一个容器 -->
    <div id="test1"></div>
    <div id="test2"></div>
    <div id="test3"></div>
    <!-- 引入 React 核心库 -->
    <script src="../js/react.development.js"></script>
    <!-- 引入 react-dom 用于支持 react 操作 DOM -->
    <script src="../js/react-dom.development.js"></script>
    <!-- 引入babel:1. ES6 ==> ES5	2. jsx ==> js-->
    <script src="../js/babel.min.js"></script>
    <script type="text/babel">
        class Person extends React.Component
            render()
                let name,age,sex = this.props
                console.log(this)
                return(
                    <ul>
                        <li>姓名:name</li>
                        <li>性别:sex</li>
                        <li>年龄:age+1</li>
                    </ul>
                )
            
        
        // 1. 数据类型,是否应该有对应的限制?
        // 2. 数据的数量,批量性传输的时候,可以使用展开运算符
        ReactDOM.render(<Person name="tom" age="18" sex="男"/>,document.getElementById('test1'))
        ReactDOM.render(<Person name="jock" age="19" sex="女"/>,document.getElementById('test2'))
        
        const p = name:'老王',age:22,sex:'男'
        // console.log("@",...p)
        ReactDOM.render(<Person ...p/>,document.getElementById('test3'))
    </script>
</body>
</html>

3. 效果展示

需求: 自定义用来显示一个人员信息的组件

  1. 姓名必须指定,且为字符串类型;
  2. 性别为字符串类型,如果性别没有指定,默认为男
  3. 年龄为字符串类型,且为数字类型,默认值为18


4. props 属性的特点:

  1. 每个组件对象都会有props(properties的简写)属性
  2. 组件标签的所有属性都保存在props中
  3. 内部读取某个属性值:this.props.propertyName
  4. 作用:通过标签属性从组件外 向组件内传递数据(只读 read only)
  5. 对props中的属性值进行类型限制和必要性限制

5. 对 props 进行限制

  1. 引入 prop-type 库,这就是专门用于限制 props 属性的一个库
  2. 导入 prop-type 库,到当前页面
  3. 根据 Person.propTypes = 进行限制

参考官方文档所示

// cli 脚手架引入方式
import PropTypes from "prop-types";
// js 引入方式
<script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>
// 类式组件
class index extends Component 
    static propTypes = 
        // 限制 list,为数组类型,必填
        list: PropTypes.array.isRequired,
        // 限制 changeitem,为一个函数,必填
        changeitem: PropTypes.func.isRequired,
        // 限制 onDelete,为一个函数,必填
        onDelete: PropTypes.func.isRequired,
    
    render() 
        const  list, changeitem, onDelete  = this.props
        return (
            <ul className="todo-main">
                <Item list=list changeitem=changeitem onDelete=onDelete />
            </ul>
        );
    

注意:

在 React v15.5 中PropTypes是react的内置对象,在 React v15.5 开始已弃用以下方式。

Person.propTypes = 
	name: React.PropTypes.string.isRequired,
	age: React.PropTypes.number


四、组件三大核心属性 3:refs与事件处理

Refs 是一个 获取 DOM节点或 React元素实例的工具。在 React 中 Refs 提供了一种方式,允许用户访问DOM 节点或者在render方法中创建的React元素。
在 React单项数据流中,props是父子组件交互的唯一方式。要修改一个子组件,需要通过的新的props来重新渲染。
但是在某些情况下,需要在数据流之外强制修改子组件。被修改的子组件可能是一个React组件实例,也可能是一个DOM元素。对于这两种情况,React 都通过 Refs的使用提供了具体的解决方案。


1. 字符串形式的代码示例

class Demo extends React.Component
     showData=()=>
         // console.log(this)
         // 专款专用:每一个ref都是唯一的,存在this.refs中
         let ipt1 = this.refs
         alert(ipt1.value)
     
     showData2=()=>
         let ipt2 = this.refs
         alert(ipt2.value)
     
     render()
         return(
             <div>
                 <input ref="ipt1" type="text" placeholder="请输入数据"/>
                 <button onClick=this.showData>点我提示左侧的数据</button>
                 <input ref="ipt2" onBlur=this.showData2 type="text" placeholder="请输入数据" />
             </div>
         )
     
 

2. 回调函数形式的代码示例

class Demo extends React.Component
    showData=()=>
        let input1 = this
        alert(input1.value)
    
    showData2=()=>
        let input2 = this
        alert(input2.value)
    
    render()
        return(
            <div>
                /* 这里是注释~ */
                <input ref= c=>this.input1 = c type="text" placeholder="请输入数据"/>
                <button onClick=this.showData>点我提示左侧的数据</button>
                <input ref=c=>this.input2 = c onBlur=this.showData2 type="text" placeholder="失去焦点提示数据" />
            </div>
        )
    

什么是回调函数?

  1. 自己写的函数
  2. 不是自己调用的
  3. 这个函数最后执行了

3. createRef 代码示例

class Demo extends React.Component
    /*
        React.createRef() 返回一个容器,容量为1,只能存一个,多余会覆盖前者
        这个容器中,可以去存储一个指定的DOM。
    */
    // 专款专用:每一个自定义的ref标记只能给唯一的DOM使用
    myRef = React.createRef() // 容量为1,只能存一个,多余会覆盖前者
    myRef2 = React.createRef()
    showData=()=>
        alert(this.myRef.current.value)
    
    showData2=()=>
        alert(this.myRef2.current.value)
    
    render()
        return(
            <div>
                <input ref= this.myRef type="text" placeholder="请输入数据"/>
                <button onClick=this.showData>点我提示左侧的数据</button>
                <input ref=this.myRef2 onBlur=this.showData2 type="text" placeholder="失去焦点提示数据" />
            </div>
        )
    

注意:

React 官方推荐使用 createRef 创建 ref 容器的方法

4. 效果展示

需求: 自定义组件, 功能说明如下:

  1. 点击按钮, 提示第一个输入框中的值
  2. 当第2个输入框失去焦点时, 提示这个输入框中的值


5. refs 使用场景

refs 通常适合在一下场景中使用:

  • 对DOM 元素焦点的控制、内容选择或者媒体播放;
  • 通过对DOM元素控制,触发动画特效;
  • 通第三方DOM库的集成。

避免使用 refs 去做任何可以通过声明式实现来完成的事情。例如,避免在Dialog、Loading、Alert等组件内部暴露 open(), show(), hide(),close()等方法,最好通过 isXX属性的方式来控制。


总结:

欢迎大家加入我的社区,在社区中会不定时发布一些精选内容:https://bbs.csdn.net/forums/db95ba6b828b43ababd4ee5e41e8d251?category=10003


以上就是 React 面向组件编程(上),不懂得也可以在评论区里问我或私聊我询问,以后会持续发布一些新的功能,敬请关注。
我的其他文章:https://blog.csdn.net/weixin_62897746?type=blog

React面向组件编程(上)

文章目录

前言:

  • React组件中默认封装了很多属性,有的是提供给开发者操作的,其中有三个属性非常重要:state、props、refs。通过这三大核心属性的使用,我们能够实现对组件的状态进行更新。

一,组件的基本理解和使用

1. 函数组件

 <script type="text/babel">
        function MyComponent()   
            return <h2>我是函数定义的组件(适用于简单组件的定义)</h2>
        
        ReactDOM.render(<MyComponent />, document.getElementById('test'))
    </script>

函数组件的渲染过程

 1.React解析了组件标签,找到了对应的组件
 2.发现这个组件是一个函数定义的,随后调用该函数,生成一个虚拟dom
 3.最后将虚拟dom转化成为真实dom,呈现在页面中

2. 类式组件

<script type="text/babel">
        class MyComponent extends React.Component 
            render() 
                return <h2>我是类定义的组件适用于复杂数据类型</h2>
            
        
        ReactDOM.render(<MyComponent />, document.getElementById('test'))
    </script>

类式组件的渲染过程

1.React解析了组件标签,找到了对应的组件
2.发现这个组件是一个类定义的,随后new出来一个实例对象,并通过该实例调用原型上的render方法
3.将render()返回的内容生成一个虚拟dom
4.最后将虚拟dom转化成为真实dom,呈现在页面中

3.组件的注意事项

组件名必须首字母大写
虚拟DOM元素只能有一个根元素
虚拟DOM元素必须有结束标签

二,组件的三大核心属性

1.state

  • state 是一个对象,它包含组件的数据状态,当状态变化时,会触发视图的更新。你可以理解它的作用跟 Vue 中的 data 对象类似。
<script type="text/babel">
        class Weather extends React.Component 
            constructor() 
                super()
                this.state = 
                    isHot: false,
                    wind: '微风'
                
                this.chang = this.chang.bind(this)
            
            render() 
                let  isHot, wind  = this.state
                return <h2 onClick=this.chang>今天的天气很 isHot ? "炎热" : "凉爽",wind</h2>
            hang() 
                console.log(this)
                this.setState(
                    isHot: !this.state.isHot
                )
            
        
        ReactDOM.render(<Weather />, document.getElementById('test'))
    </script>

1. 注意事项

1.组件中render方法中的this为组件实例对象
2.组件自定义的方法中this为undefined,如何解决?
	1.强制绑定this: 通过函数对象的bind()
	2.箭头函数
3.状态数据,不能直接修改或更

2.简写方式

<script type="text/babel">
        class Weather extends React.Component 
           state = 
                    isHot: false,
                    wind: '微风'
                

            render() 
                let  isHot, wind  = this.state
                return <h2 onClick=this.chang>今天的天气很 isHot ? "炎热" : "凉爽",wind</h2>
            

            chang = ()=>  
                this.setState(
                    isHot: !this.state.isHot//这里的修改是一种合并,对比属性的变化,如果有赋新值,没有则跳过
                )
            
        
        ReactDOM.render(<Weather />, document.getElementById('test'))
        let a = new Weather()
</script>

设置状态:setState

setState(object nextState[, function callback])

不能在组件内部通过 this.state 修改状态,因为该状态会在调用 setState() 后被替换。

setState() 并不会立即改变 this.state,而是创建一个即将处理的 statesetState() 并不一定是同步的,为了提升性能 React 会批量执行 stateDOM 渲染。

setState() 总是会触发一次组件重绘,除非在 shouldComponentUpdate() 中实现了一些条件渲染逻辑。


2.props

  • React 中组件通过 props 属性接收外部传入的数据,这点 Vue 跟 React 是一致的
  • react 中说的单向数据流值说的就是 props,根据这一特点它还有一个作用:组件之间的通信
  • props 本身是不可变的,但是有一种情形它貌似可变,即是将父组件的 state作为子组件的 props,当父组件的 state 改变,子组件的 props 也跟着改变,其实它仍旧遵循了这一定律:props 是不可更改的
<script type="text/babel">
  class MyComponent extends React.Component 
    render() 
      return (
        <ul>
          <li>this.props.name</li>
          <li>this.props.age</li>
        </ul>
      );
    
  
  ReactDOM.render(
    <MyComponent name="Bob" age="18" />,
    document.getElementById("test")
  );
</script>

props的特点:

  1. 每个组件对象都会有props(properties的简写)属性
  2. 组件标签的所有属性都保存在props中
  3. 内部读取某个属性值:this.props.propertyName
  4. 作用:通过标签属性从组件外 向组件内传递数据(只读 read only)
  5. 对props中的属性值进行类型限制和必要性限制

对props进行限制

  1. 引入 prop-type 库,这就是专门用于限制 props 属性的一个库
  2. 导入 prop-type 库,到当前页面
  3. 根据 Person.propTypes = 进行限制
class MyComponent extends React.Component 
  render() 
    return (
      <ul>
        <li>this.props.name</li>
        <li>this.props.age</li>
      </ul>
    );
  


// 校验类型
MyComponent.propTypes = 
  name: PropTypes.string, // 这里的 PropTypes 变量是全局挂载的
  age: PropTypes.number,
;

ReactDOM.render(
  <MyComponent name="Bob" age=18 />,
  document.getElementById("test")
);

props的简写

<script type="text/babel">
        class Weather extends React.Component 
            constructor(props) //是否接受,取决于是否使用外部数据
                super(props)//只能上面接受了props,super()就去传递,否则后续的使用,可能就会出现问题
            
            static propTypes = 
                name: PropTypes.string.isRequired,//限制name为字符串类型,必填
                // age: PropTypes.number,
                sex: PropTypes.string,
                speak: PropTypes.func
            
            static defaultProps = 
                sex: '男',
            
            render() 
                let  name, age, sex  = this.props
                return (
                    <ul>
                        <li>姓名:name</li>
                        <li>性别:sex</li>
                        <li>年龄:age + 1</li>
                    </ul>
                )
            
        
     ReactDOM.render(<Weather name="tom" age=26 sex="女" />, document.getElementById('test'))

</script>

函数组件使用props

<script type="text/babel">
  // 函数组件
  function MyComponent(props) 
    return (
      <ul>
        <li>props.name</li>
        <li>props.age</li>
      </ul>
    );
  
  // 校验类型
  MyComponent.propTypes = 
    name: PropTypes.string,
      age: PropTypes.number,
  ;

  ReactDOM.render(
    <MyComponent name="Bob" age=18 />,document.getElementById("test")
  );
</script>

3.ref

  • React 中的 Refs 可以让我们访问 DOM 节点,它有三种使用方式:字符串方式回调函数式createRef
  • 在 React 中 Refs 提供了一种方式,允许用户访问DOM 节点或者在render方法中创建的React元素
  • 在 React单项数据流中,props是父子组件交互的唯一方式。要修改一个子组件,需要通过的新的props来重新渲染。
    但是在某些情况下,需要在数据流之外强制修改子组件。被修改的子组件可能是一个React组件实例,也可能是一个DOM元素。对于这两种情况,React 都通过 Refs的使用提供了具体的解决方案。

字符串方式

<script type="text/babel">
  class MyComponent extends React.Component 

    handleAlert = () => 
      // 在 refs 中获取定义的 ref 标识
      const  myInput  = this.refs;
      console.log(myInput); // <input type="text">
      alert(myInput.value);
    ;

    render() 
      return (
        <div>
          /* 使用 ref="" 方式直接定义字符串标识  */
          <input ref="myInput" type="text" />
          <button onClick=this.handleAlert>alert</button>
        </div>
      );
    
  

  ReactDOM.render(<MyComponent />, document.getElementById("test"));
</script>

回调函数方式

<script type="text/babel">
  class MyComponent extends React.Component 
    
    handleAlert = () => 
      // 直接从组件实例上获取 myInput
      console.log(this.myInput); // <input type="text">
      alert(this.myInput.value);
    ;

    render() 
      return (
        <div>
          /* ref 直接定义成一个回调函数,参数就是节点本身,将它赋值给组件的一个 myInput 属性 */
          <input ref=(ele) => (this.myInput = ele) type="text" />
          <button onClick=this.handleAlert>alert</button>
        </div>
      );
    
  

  ReactDOM.render(<MyComponent />, document.getElementById("test"));
</script>

React官方提示:

如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。

createRef -官方推荐使用

<script type="text/babel">
  class MyComponent extends React.Component 
    // 创建 ref
    myInput = React.createRef();

    handleAlert = () => 
      console.log(this.myInput.current); // 这里需要注意,元素是在 current 属性上
      alert(this.myInput.current.value);
    ;

    render() 
      return (
        <div>
          /* 将创建好的 ref 附加到元素上 */
          <input ref=this.myInput type="text" />
          <button onClick=this.handleAlert>alert</button>
        </div>
      );
    
  

  ReactDOM.render(<MyComponent />, document.getElementById("test"));
</script>

上面就是使用 React.createRef() 方法创建 ref 的方式,特别需要注意的是,创建出来的 ref 的值是一个对象,我们需要的 DOM 元素是放在对象的 current 属性上,如上面的 this.myInput.current。

总结

以上就是React面向组件编程中的一部分。希望本篇文章能够帮助到你,若有错误欢迎指出,不懂得可以评论区或者私信问我,我也会一 一解答。谢谢观看!
我的其他文章:https://blog.csdn.net/m0_60970928?type=blog

以上是关于React 面向组件编程(上)的主要内容,如果未能解决你的问题,请参考以下文章

React 面向组件编程(上)

React面向组件编程(上)

如何使用 j_security_check 在 React.JS 应用程序上对用户进行身份验证

React.js 常见问题

在 React Native WebView 中隐藏 React.js 组件

如何从 React JS 中父组件上的对象循环子组件中的项目