React学习笔记:初识JSX和Webcomponents(一)

395 阅读6分钟

React的使用离不开JSX语法和关于Webcomponent的构造。 个人认为,React相比于Vue更贴近官方定义组件本身,并且其灵活性更大。
React是什么都具备但需要自己编写,Vue是限制你在其内部编写。
两者并无优劣。


React渲染

和其他组件化框架类似,都会在main/index.js进行挂载。
React要求必须挂载在唯一根节点下。
然后调用React提供的函数React.creatRoot获得实例root,而后调用render进行挂载渲染。

JSX

JSX语法其实是相当于定义JS变量去接受一个标签或标签组。 注意适用方法

JSX的使用与定义

const customBtn = <button>我的按钮</button>;

同时JSX支持内部嵌套变量,但需要用{}标识。

const myName="rookie"
const customBtn = <button>{myName}</button>;

在渲染的时候会自动进行字符检索然后替换。
当然在标签上也是适用的。

const myName="rookie"
const btnID="clickBTN"
const customBtn = <button id={btnID}>{myName}</button>;

值得注意的是标签内的属性需要小驼峰写法,class在React中被替换成className.

const myName="rookie"
const btnID="clickBTN"
const handleClick=()=>{console.log('我被点击了')}
const customBtn = <button 
                    id={btnID}
                    className='xxxxx'
                    onClick={handleClick}>
                    {myName}
                    </button>;

JSX深入

既然任何{}内的内容都会被识别替换,那括号里面再放入一个JSX是不是同样能够被正确识别?
如果有看过Webcomponent提案的同学看到这里可能已经明白React怎么进行组件嵌套.
举个例子,我自定义一个Form表单组件,同时将各个input和btn当做参数传入,那是否可以直接在Form表单组件内使用?
答案是可以的

const myInput=<input onChange={changeClick}> </input>
const myBtn =<button style="xxxx"></button>
const myForm=(
            <form>
                {myInput}
                {myBtn}
             </form>
             )

这里就不得不提到组件这一概念了。毕竟可复用和提高开发效率才是框架的本质而不是搁着互相嵌套着玩。

组件化

先在这里说个结论,组件开发的主流和趋势是趋向于调用HOOK的函数组件而不是Class组件。 Hook的使用和普及极大程度上简化了组件设计和实现的难度。 这里只记录组件的编写但是建议各位认真看一下为什么要使用Hook和Hook调用的原理。

Class组件

class组件就是按照ES6的写法编写class组件继承React内部的Components类实现。
熟悉ES6语法的同学可能知道extends另一个类就必须要实现其构造函数,通过super()关键字实现。
在这里组件会接受一个附着在标签上的props,然后必须在内部用super传递给Component。 ``

import {Component} from 'React'

class MyFirstComponent extends Component{
    construcor(props){
        super(props)
    }
    render(){
        //这里是你的JSX
    }
}

使用如下

    //标签上的属性都会被当做props传递给类。
    //ref不会传递!后续会讲但是这里暂且不表。
    <MyFristComponent name="小唐同学" clickMethod={xxx}></MyFristComponent>

React没有插槽这一概念
如果你需要把组件传递给另外一个组件可以直接在标签上传递或者放在组件内,而组件通过props.children来接受。

函数式组件

目前主流主流主流
中所周知react会提供很多内部的hooks或者你会自定义hooks,而function可以完美调用此类hooks。
函数组件必须返回JSX或者实现render函数


function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

调用如下

<Welcome name="Sara" />

State和生命周期。

State,组件内部的状态和变量,由组件内部管理,其他组件无法插手。
生命周期,组件进行的程度和当前周期的回调。
如果学过Vue的同学可能知道一个组件内部的逻辑应当由组件本身管理,而外部只需要提供props就好,无需关心组件内部,只要调用就好。这在React同样适用。 划重点

React的props为只读,不能修改props。
React提供State和setState来维护组件内部的逻辑
React提供组件生命周期的钩子函数,但是函数组件必须用React提供的其他函数来实现Hook。


这里直接上官网的源码讲解。

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {    this.setState({      date: new Date()    });  }
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Clock />);
  1. 构造Class类组件并继承来自React的component类。
  2. 实现构造函数constructor和super。其中props为接受到的参数(即标签上的参数)
  3. 初始化state对象。
  4. 在Class内部实现可以修改state的方法tick
  5. 在componentDidMount实现定时器获取时间
  6. 在componentWillUnmount销毁定时器。 具体的生命周期和生命周期作用建议查阅官网中文文档。

事件处理 循环 条件判断

既然将jsx当做一个JS变量对待,那么慢能够使用于JS的语法当然也可以在JSX身上使用。
在这里值得提醒的是注意世间绑定中的this。
在函数组件内可能不容易差距但是在class组件就很容易发现。
若在JSX上调用方法来修改state需要将this指向class本身,否则无法找到this.setState这个方法。

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // 为了在回调中使用 `this`,这个绑定是必不可少的    
    this.handleClick = this.handleClick.bind(this);  
   }

  handleClick() {    this.setState(prevState => ({      isToggleOn: !prevState.isToggleOn    }));  }
  render() {
    return (
      <button onClick={this.handleClick}>        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

条件判断

JSX和React的条件判断略微复杂。常规做法有如下 根据判断条件返回不同的JSX。

function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}
function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {    
      return <UserGreeting />;  
  }  
  return <GuestGreeting />;}

这要做的代价就是重复编写无意义的代码。效率低下。 另外一种做法是抽象代码,简化流程。

function Greeting(props){
    const welcomeWord=props.isLoggedIn?'Welcome back!':'Please sign up';
    return <h1>{welcomeWords}</h1>
}

这要简写代码后舒服多了,反正你只需要调用他就行无需关心组件内部实现。
既然用到了三元条件符那么&&就可以登场咯。
理解运算符短路 如果&&前面为true那么返回的总是符号后面的语句

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {
          unreadMessages.length > 0 &&        
            <h2>          
            You have {unreadMessages.length} unread messages.        
            </h2>      
      }    
   </div>
  );
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  <Mailbox unreadMessages={messages} />,
  document.getElementById('root')
)

循环、列表

只要返回的是JSX对象那么实现就可以参考JS语法本身,但是注意要在实现的语句上加上Key否则会造成渲染错误。

function ListItem(props) {
  // 正确!这里不需要指定 key:  
  return <li>{props.value}</li>;}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map( number =>
    // 正确!key 应该在数组的上下文中被指定    
    <ListItem key={number.toString()} value={number} />  
    );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

在哪里实现的循环在哪里提供key

到这里其实已经明白React组件的操作和基本。至于值绑定或者通信这种东西已经能隐隐约约感觉到门道了。
这里只说明React的基础,更深一步了建议阅读官网。 React官方文档