React面向组件编程(上)

Posted 程序员--韩同学

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

2. React面向组件编程

1. 基本理解和使用

先在Google安装React Develop Tools插件。

以美团页面为例,安装成功后可以在开发者工具看到添加了Components和Prifiler选项:


react中定义组件

  1. 函数式组件:适用于简单组件的定义


执行ReactDOM.render(<Demo/>, document.getElementById('test'))之后,发生了什么?

  1. React解析组件标签,找到Demo组件
  2. 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,呈现在页面中

  1. 类式组件:适用于复杂组件的定义

执行ReactDOM.render(<MyComponent />, document.getElementById('test'))之后,发生了什么?

  1. React解析组件标签,找到MyComponent组件
  2. 发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法
  3. 将render返回的虚拟DOM转为真实DOM,呈现在页面中

2. 组件三大核心属性之:state

state是组件对象最重要的属性,值是对象(可以包含多个 key-value 的组合)。

可以通过更新组件的state来更新对应的页面显示(重新渲染组件)。

注意:

  1. 组件中render方法中的this为组件实例对象
  2. 解决组件自定义的方法中this为undefined的问题:
    • 强制绑定this:通过函数对象的bind()
    • 箭头函数
  3. 状态数据, 不能直接修改或更新
<body>
    <div id="test"></div>

    <script src="../../js/react.development.js"></script>
    <script src="../../js/react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>


    <script type="text/babel">
        // 1. 创建类式组件
        class Weather extends React.Component 
            constructor(props) 
                super(props);
                // 初始化状态
                this.state = 
                    isHot: true
                
                // 解决changeWeather中this的指向问题
                this.changeWeather = this.changeWeather.bind(this);
            

            // changeWeather放在Weather的原型对象上,供实例调用
            // changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
            changeWeather() 
                // 类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
                console.log(this); // undefined

                // 获取原来的isHot值
                const isHot = this.state.isHot
                // 状态(state)不能直接更改,要借助内置API(setState)去更改
                // this.state.isHot = !isHot // 错误写法
                this.setState(
                    isHot: !isHot
                )
            

            render() 
                // 读取状态
                const  isHot  = this.state;
                return <h1 onClick=this.changeWeather>今天天气很isHot ? '炎热' : '凉快'</h1>
            
        

        // 2. 渲染组件到页面
        ReactDOM.render(<Weather />, document.getElementById('test'));
    </script>
</body>

state的简写方式:

    <script type="text/babel">
        class Weather extends React.Component 
            state = 
                isHot: true
            

            // 自定义方法,要用赋值语句的形式 + 箭头函数
            changeWeather = () => 
                const isHot = this.state.isHot
                this.setState(
                    isHot: !isHot
                )
            

            render() 
                const  isHot  = this.state;
                return <h1 onClick=this.changeWeather>今天天气很isHot ? '炎热' : '凉快'</h1>
            
        

        ReactDOM.render(<Weather />, document.getElementById('test'));
    </script>

3. 组件三大核心之:props

每个组件都会有 props 属性,组件标签的所有属性都保存在 props 中。

3.1 props基础

props的简单使用:

    <script type="text/babel">
        // 创建组件
        class Person extends React.Component 
            render() 
                console.log(this);

                // 提前解构赋值,就可以直接使用解构之后的值
                const  name, age, gender  = this.props;
                
                return (
                    <ul>
                        <li>姓名:this.props.name</li>
                        <li>性别:this.props.age</li>
                        <li>年龄:this.props.gender</li>

                        <br />

                        <li>姓名:name</li>
                        <li>性别:age</li>
                        <li>年龄:gender</li>
                    </ul>
                )
            
        

        ReactDOM.render(<Person name="张三" age="12" gender="男" />, document.getElementById('test'));
    </script>


批量传递props:

    <script type="text/babel">
        // 创建组件
        class Person extends React.Component 
            render() 
                console.log(this);

                // 提前解构赋值,就可以直接使用解构之后的值
                const  name, age, gender  = this.props;

                return (
                    <ul>
                        <li>姓名:name</li>
                        <li>性别:age</li>
                        <li>年龄:gender</li>
                    </ul>
                )
            
        

        // 实际开发中获取到的数据一般是一个对象
        const p =  name: "张三", age: "12", gender: "男" 
        // ReactDOM.render(<Person name="张三" age="12" gender="男" />, document.getElementById('test'));
        ReactDOM.render(<Person ...p />, document.getElementById('test'));
    </script>

对props进行限制:

<body>
    <div id="test"></div>

    <script src="../../js/react.development.js"></script>
    <script src="../../js/react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>

    <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script src="../../js/prop-types.js"></script>


    <script type="text/babel">
        // 创建组件
        class Person extends React.Component 
            render() 
                console.log(this);

                // 提前解构赋值,就可以直接使用解构之后的值
                const  name, age, gender  = this.props;

                return (
                    <ul>
                        <li>姓名:name</li>
                        <li>性别:age + 1</li>
                        <li>年龄:gender</li>
                    </ul>
                )
            
        

        // 对标签属性做类型、必要性的限制(注意p的大小写)
        Person.propTypes = 
            // name: PropTypes.string, // 限制name类型为字符串
            name: PropTypes.string.isRequired, // 设置name为字符串且必传
            gender: PropTypes.string,
            age: PropTypes.number,
            speak: PropTypes.func // 限制speak为函数
        
        // 设置默认值
        Person.defaultProps = 
            gender: '保密',
            age: 18
        

        function speak() 
            console.log("hello");
        

        // 实际开发中获取到的数据一般是一个对象
        ReactDOM.render(<Person name="张三" age=12 speak=speak />, document.getElementById('test'));
    </script>
</body>

props是只读的:

this.props.name = '李四'; // props是只读的,此行代码会报错

props的简写方式:

    <script type="text/babel">
        // 创建组件
        class Person extends React.Component 
            // 对标签属性做类型、必要性的限制(注意p的大小写)
            static propTypes = 
                name: PropTypes.string.isRequired, // 设置name为字符串且必传
                gender: PropTypes.string,
                age: PropTypes.number,
                speak: PropTypes.func // 限制speak为函数
            
            
            // 设置默认值
            static defaultProps = 
                gender: '保密',
                age: 18
            

            render() 
                console.log(this);

                // 提前解构赋值,就可以直接使用解构之后的值
                const  name, age, gender  = this.props;

                return (
                    <ul>
                        <li>姓名:name</li>
                        <li>性别:age + 1</li>
                        <li>年龄:gender</li>
                    </ul>
                )
            
        

        function speak() 
            console.log("hello");
        

        // 实际开发中获取到的数据一般是一个对象
        ReactDOM.render(<Person name="张三" age=12 speak=speak />, document.getElementById('test'));
    </script>

3.2 类式组件中的构造器与props

// 构造器是否接收props,是否传递给super,取决于是否希望在构造器中通过this访问props
constructor(props) 
    super(props);
    console.log(this.props); // name: '张三', gender: '保密', age: 18


// constructor() 
//     super();
//     console.log(this.props); // undefined
// 

3.3 函数式组件使用props

<script type="text/babel">
    function Person(props) 
        const  name, age, gender  = props;
        return (
            <ul>
                <li>姓名:name</li>
                <li>性别:age + 1</li>
                <li>年龄:gender</li>
            </ul>
        )
    
    ReactDOM.render(<Person name="张三" gender="男" age=18 />, document.getElementById('test'));
</script>

4. 组件三大核心之:ref

组件内的标签可以定义ref属性来标识自己。

4.1 ref基础

字符串形式的ref(不建议使用):

<script type="text/babel">
    // 创建组件
    class Demo extends React.Component 
        // 展示左侧输入框的数据
        showData = () => 
            const  input1  = this.refs;
            alert(input1.value);
        
        // 展示右侧输入框数据
        showData2 = () => 
            const  input2  = this.refs;
            alert(input2.value);
        
        render() 
            return (
                <div>
                    <input ref="input1" type="text" placeholder="点击按钮提示数据" />
                    <button onClick=this.showData>点击提示左侧数据</button>
                    <input ref="input2" onBlur=this.showData2 type="text" placeholder="失去焦点提示数据" />
                </div>
            )
        
    
    // 渲染组件到页面
    ReactDOM.render(<Demo />, document.getElementById('test'));
</script>

回调函数形式的ref:

<script type="text/babel">
    // 创建组件
    class Demo extends React.Component 
        // 展示左侧输入框的数据
        showData = () => 
            const  input1  = this;
            alert(input1.value);
        
        render() 
            return (
                <div>
                    <input ref=currentNode => this.input1 = currentNode type="text" placeholder="点击按钮提示数据" />
                    <button onClick=this.showData>点击提示左侧数据</button>
                </div>
            )
        
    
    // 渲染组件到页面
    ReactDOM.render(<Demo />, document.getElementById('test'));
</script>

ref 回调函数以内联函数的方式定义时,在更新过程中会被执行两次:

  • 第一次传入参数null(初始化)
  • 第二次传入参数DOM元素
<script type="text/babel">
    // 创建组件
    class Demo extends React.Component 
        state = 
            isHot: false
        
        // 展示左侧输入框的数据
        showData = () => 
            const  input1  = this;
            alert(input1.value);
        
        // 改变天气
        changeWeather = () => 
            const  isHot  = this.state;
            this.setState(
                isHot: !isHot
            React 面向组件编程(上)

React面向组件编程(上)

React.js 常见问题

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

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

如何在react js中的onclick事件上隐藏和显示路由器组件