浅谈React的两种组件

1. 元素与组件

const div = React.createElement( 'div',...)   // 这是一个 React 元素
const Div = ()=>React.createElement( 'div' ..)    // 这是一个 React 组件
什么是组件?
  • 能跟其他物件组合起来的物件(零件),就是组件
  • 组件并没有明确的定义,靠感觉理解就行
  • 就目前而言,一个返回React元素的函数就是组件
  • 在Vue里,一个构造选项就可以表示一个组件

2. React的两种组件及数据的读写

1.函数组件
function Welcome(props){
    return <h1>Hello,{props.name}</h1>;
}

使用方法

<Welcome name='frank' />
2.类组件
class Welcome extends React.Component {
    render(){
        return <h1>Hello,{this.props.name}</h1>
    }
}

使用方法

<Welcome name='frank' />
组件的解析过程

上面的 welcome 会被翻译成什么呢?

  • <div />   <!-- 会被翻译为React.createElement('div') -->
    
  • <Welcome /> <!-- 翻译为React.createElement(Welcome) -->
    
React.createElement 的逻辑
  • 如果传入一个字符串'div'(原生标签),则会创建一个div(虚拟DOM)
  • 如果传入一个函数,则会调用该函数,获取其返回值
  • 如果传入一个,则在类前面加个new(这会导致执行 constructor),获取一个组件对象,然后调用对象的 render 方法,获取其返回值
//  React 小试牛刀
import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
    return (
        <div className='App'>
            爸爸
            <Son/>
        </div>
    );
}

class Son extends React.Component {
    constructor() {
        super();
        this.state = {
            n: 0
        }
    }

    add() {
        this.setState({n: this.state.n + 1});
    }

    render() {
        return (
            <div className='Son'>
                儿子 n:{this.state.n}
                <button onClick={() => this.add()}>+1</button>
                <Grandson/>
            </div>
        );
    }
}

const Grandson = () => {
    const [n, setN] = React.useState(0)
    return (
        <div className='Grandson'>
            孙子 n:{n}
            <button onClick={() => setN(n + 1)}>+1</button>
        </div>
    )
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App/>, rootElement);

3. React组件使用 props
  1. 添加 props 外部数据 不可直接写

    • 类组件 直接读取属性 this.props.xxx

    • <Son props='你好啊'/>   // 直接添加属性  变量则使用{xxx}
          
        class Son extends React.Component {
          constructor() {
              super();
              this.state = {
                  n: 0
              }
          }
      
          add() {
              this.setState({n: this.state.n + 1});
          }
      
          render() {
              return (
                  <div className='Son'>
                      儿子 n:{this.state.n}
                      他说:{this.props.props}    // 读取属性
                      <button onClick={() => this.add()}>+1</button>
                      <Grandson/>
                  </div>
              );
          }
      }  
      
      
    • 函数组件读取参数 props.xxx

    • <Grandson sunzi='你是孙子'/>    //  参数传递同类组件
            
          const Grandson = (props) => {   // 函数组件使用函数参数来接收props数据
          const [n, setN] = React.useState(0)
          return (
              <div className='Grandson'>
                  孙子 n:{n}
                  他说:{props.sunzi}    // 接收数据
                  <button onClick={() => setN(n + 1)}>+1</button>
              </div>
          )
      }
      
  2. 添加 state 内部数据

    • 类组件用 this.state 读,this.setState

    • class Son extends React.Component {
          constructor() {
              super();
              this.state = {    // 必须写在 super 下面声明state
                  n: 0   // 初始化
              }
          }
      
          add() {
              this.setState({n: this.state.n + 1});   // setState 写属性
              //  只有使用 setState 才能更新UI 而且是异步更新数据
              //  React中不提倡改变之前的属性 要产生新的对象
          }
      
          render() {
              return (
                  <div className='Son'>
                      儿子 n:{this.state.n}    // 读数据
                      他说:{this.props.props}
                      <button onClick={() => this.add()}>+1</button>
                      <Grandson sunzi='你是孙子'/>
                  </div>
              );
          }
      }
      
    • setState 高级用法 函数写法

    • add() {    // 还是上面的 add 方法
             this.setState((state) => {    // setState 函数写法
                 return {
                     n:state.n + 1
                 }
             });   
         }
      
    • 函数组件 使用 useState 返回数组,第一项读,第二项写

    • const Grandson = (props) => {
          const [n, setN] = React.useState(0)   //初始值  析构赋值写法
          return (
              <div className='Grandson'>
                  孙子 n:{n}
                  他说:{props.sunzi}
                  <button onClick={() => setN(n + 1)}>+1</button>
              </div>    
          )    // setN 不会改变 n 的值,只会产生一个新的n
      }
      
  3. 类组件的注意事项

    • 组件中直接使用 this.state.n + = 1是不会更新 UI
    • 其实n已经改变,只不过UI不会自动更新而已
    • 调用setState才会触发UI更新(异步更新)
    • 因为 React没有像 Vue 监听data一样监听 state
    • setState之后,state不会马上改变,立马读state会失败
    • 更推荐的方式是setState(函数)
    • 不推荐 this.setState(this.state) 这种写法
    • React 希望我们不要修改旧 state(不可变数据)
    • 常用代码:setState({n: state.n+1})
  4. 复杂情况写的的 state

类组件的 setState 会自动合并旧的数据
class Son extends React.Component {
    constructor() {
        super();
        this.state = {
            n: 0,     //  这里有两个值 m n 
            m:0
        }
    }

    addN() {   
        this.setState({n: this.state.n + 1});   // 这里修改n时,react会把其他的数据(这里指的是m)沿用旧的值  但也只是第一层数据,第二层数据不会合并
    }
    addM() {
        this.setState({m: this.state.m + 1});
    }

    render() {
        return (
            <div className='Son'>
                儿子 n:{this.state.n}
                他说:{this.props.props}
                <button onClick={() => this.addN()}>+1</button>
                m的值:{this.state.m}
                <button onClick={() => this.addM()}>+1</button>
                <Grandson sunzi='你是孙子'/>
            </div>
        );
    }
}
函数组件的 setState 不会自动合并旧的数据
//  函数组件第一层也不会合并
const Grandson = (props) => {
    const [state, setState] = React.useState({
        m: 0,
        n: 0
    })
    return (
        <div className='Grandson'>
            孙子 n:{state.n}
            <button onClick={() => setState({n: state.n + 1})}>n+1</button>
            孙子 m:{state.m}
            <button onClick={() => setState({m: state.m + 1})}>m+1</button> 
        </div>
    )
}
//  点击按钮 另一个数据会变成 undefined 从而不显示 

多层数据的合并方法一------使用 ... 运算符

// 应该先拷贝之前的数据
const Grandson = (props) => {
    const [state, setState] = React.useState({
        m: 0,
        n: 0
    })
    return (
        <div className='Grandson'>
            孙子 n:{state.n}
            <button onClick={() => setState({...state,n: state.n + 1})}>n+1</button>
            孙子 m:{state.m}
            <button onClick={() => setState({...state,m: state.m + 1})}>m+1</button>
        </div>
    )
}

多层数据的合并方法二------使用 Object.assign

changeUser(){
        const user = Object.assign({},this.state.user)
        user.name = '大欧'
        this.setState({
            //  这里 m m 不会被置空
            user:user
        })
    }
// 拷贝了user对象

3. 事件绑定

类组件的事件绑定
<button onClick = {() => this.addN()}> n+1 </button>

传一个函数给onClick即可,注意C大写

思考一个问题,下面这样写行不行

<button onClick= (this.addN) >n+1</button> <!-- 错误写法 -->

有问题,上面这样会使得 this.addN函数体里面的 this 变成 window

目前类组件绑定事件的最好写法:

addN = () => this.setState({n:this.state.n + 1})  // 定义函数名 addN
// 这样写是实例对象上面的方法
<button onClick = {this.addN}> n+1 </button>   // 使用该函数
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 什么是组件 在Vue中,一个构造选项就可以表示一个组件,构造选项(有data,methods等等),而在React...
    luci_dity阅读 1,449评论 0 0
  • 什么是组件 能跟其他物件 组 合起来的物 件 ,就是组件 组件并没有明确的定义,靠感觉理解 就行 就目前而言,一个...
    PYFang阅读 3,696评论 0 0
  • React.createElement 如果传入字符串div,会创建一个div 如果传入一个函数,则会调用该函数,...
    fanison阅读 1,280评论 0 0
  • 懒加载 :为什么 解决页面假死状态 单页面vue和react,,只有一个HTML,首屏加载慢,后期切换比较快,不利...
    知命者夏洛特阅读 19,786评论 0 16
  • React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归; 具体的三种方式: 函数式定义的无...
    一二三四五_6ce3阅读 3,666评论 0 0