antd-pro快速入门之一--react基础

React快速入门

概述

本文读者对象为有一定编程基础、会基础html、css、javascript/es6的人,没有这些基础看起来有点难。本文用简单明了的语言来陈述,有些地方不太严谨不太准确,但我认为不影响入门就没问题。

编码实验环境:https://codepen.io Pen,pen setting 设置js环境,Javascript Preprocessor 选Babel,资源添加https://unpkg.com/react@16/umd/react.development.jshttps://unpkg.com/react-dom@16/umd/react-dom.development.js。如下图:

react 是在js里写html

没学过react前,一般都是在html里写js代码,html代码都是写在后缀为html的文件写的,但是react不同,react代码是写在js脚本里的,是写在后缀为js的文件里的。这是编程思维习惯上的不同,入坑react,一定要转过弯来。react组件,html元素是一种数据类型一样和字符串、数值、布尔类型一样赋值给变量,当函数返回值。照例,来个Hello World:

const hello=<h1>Hello World!</h1>;
ReactDOM.render(
  hello,
  document.getElementById('root')
);

看看效果:

解释一下这几行代码:定义一个常量 hello,并将<h1>Hello World!</h1>赋值给它,后通过ReactDOM.render把hello渲染(展示)到html文档里id 为root的元素里,ReactDom对角及其方法render是react里定义的,就这样用就行了。需要注意的是,react组件、html元素赋值给变量,作为函数返回值是,一定是个整体,比如:

<div>hello world</div>
<div>
    <span>hello</span>
    <span>world</span>
</div>

就是说,只有一个根元素,里面有多少内容都行,但是根元素只有一个,但是下面就不是一个整体

<span>hello</span>
<span>world</span>

它是两个并列的元素,不是一个整体。所以,下面的代码是没有问题的:

const element=<div>
                <span>hello</span>
                <span>world</span>
             </div>;

来看看效果:

但是下面的代码是会出错的:

const elements=<span>hello</span><span>world</span>;

但是如果不想要一个元素把他们包住怎么办?把它们放到数组里,赋值给elements 。

const elements=[<span>hello</span>,<span>world</span>];//这个跟 const numbers=[1,2]是一个样的;

还可以这样写,效果是一样的:

const elements=[];
elements.push(<span>hello</span>);
elements.push(<span>world</span>);

看看效果:

不过元素数组要求每个元素要有个key属性,值可以是数值,字符串等,但必须唯一。像上面这个没有key属性,console里可以看到报错:

下面这样就不会报这个错了:

const elements=[<span key="1">hello</span>,<span key="2">world</span>];
//或者
const elements=[];
elements.push(<span key="1">hello</span>);
elements.push(<span key="2">world</span>);

react元素作为函数返回值:

function sayHello(){
    return <h1>Hello World!</h1>;
}
const element=sayHello();

总之记住,react组件,html元素也是一种数据类型,跟其它数据类型一样进行操作。

逻辑控制、数据操作

实际编程的时候,我们不是操作一些静态的固定的html元组,还要显示数据,根据不同的条件显示不同的html。下面进行示范。

html中插入变量值,使用{ }大括号括起,如:

const name="Garrett";
const element=<h1>Hello {name}</h1>;

加入逻辑判断:

function sayHello(name){
    return <h1>Hello {name?name:"World"}!</h1>;
}
let element;
element=sayHello(); //element=<h1>Hello World!</h1>
element=sayHello("Garrentt"); //element=<h1>Hello Garrentt!</h1>

多条数据显示:

const arr=["React","Vue","Angular"];
const elements=arr.map((item,index)=><li key={item}>{index+1}.{item}</li>);
const element=<div>流行前端技术:
                  <ul>{elements}</ul>
              </div>;

表格数据:

css增加样式:

td ,th,table{
  border: 1px solid #3e3e3e;
}
th {
  width: 60px;
}

js代码:

const students=[
            {name:"潘小莲",sex:"女",class:"三(2)班"},
            {name:"武小郎",sex:"男",class:"三(2)班"},
            {name:"西小庆",sex:"男",class:"三(1)班"}
          ];
const elements=students.map((item)=><tr key={item.name}>
                              <td>{item.name}</td>
                              <td>{item.sex}</td>
                              <td>{item.class}</td>
                          </tr>);
const element=<table>
             <thead><tr><th>姓名</th><th>性别</th><th>班级</th></tr></thead>
             <tbody>{elements.length>0?elements:<tr><td colSpan="3">没有数据</td></tr>}</tbody>
          </table>;

结果显示:

改students=[ ]时,结果:

React组件

render方法

React组件类必须继承于React.Component,必须有个render()方法展示要显示的内容:

class HelloMessage extends React.Component {
  render() {
    return (
      <h1>
        Hello World!
      </h1>
    );
  }
}
ReactDOM.render(
  <HelloMessage/>,
  document.getElementById('root')
);

组件属性和状态props和state

组件的数据来自外部和自身产生,props是外部传给组件的,在组件内部使用this.props访问,内部数据使用state维护,用this.state访问和使用this.setState({name:value})的形式修改。当props和state数据改变时,组件都会调用render()方法来更新界面。state在构造函数中初始化。

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { seconds: 0 };
  }
  tick() {
    this.setState(state => ({
      seconds: state.seconds + 1
    }));
  }
  componentDidMount() {
    this.interval = setInterval(() => this.tick(), 1000);
  }
  componentWillUnmount() {
    clearInterval(this.interval);
  }
  render() {
    return (
      <div>
            {this.props.name}: {this.state.seconds}
      </div>
    );
  }
}
ReactDOM.render(
  <Timer name="timer" />,
  document.getElementById('root')
);

需要注意的是,不能在render()方法中更新state,也就是说,不能在render()方法中调用this.setState方法,因为state一改变,就要调用render(),一render()又调用setState,这样死循环。

受控组件和非受控组件、事件绑定

受控和非受控组件是针对表单元素来说的,比如input标签,input的value值必须是我们设置在constructor构造函数的state中的值,然后,通过onChange触发事件来改变state中保存的value值,这样形成一个循环的回路影响。也可以说是React负责渲染表单的组件仍然控制用户后续输入时所发生的变化。也就是说input中的value值通过state值获取,input onChange事件改变state中的value值,input中的value值又从state中获取,这就是受控组件。非受控也就意味着我可以不需要设置它的state属性,而通过ref来操作真实的DOM。

class ComponentDemo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {ctlText: '',unCtlText:'' };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.ref=React.createRef();
  }
  render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <label htmlFor="ctl"> 受控组件 </label>
          <input
            id="ctl"
            onChange={this.handleChange}
            value={this.state.ctlText}
          />
            <label htmlFor="unCtl"> 非受控组件 </label>
          <input
            ref={this.ref}
            id="unCtl"
          />
          <button>submit</button>
        </form>
        <div>
          <div>受控组件值:{this.state.ctlText}</div>
          <div>非受控组件值:{this.state.unCtlText}</div>
        </div>
      </div>
    );
  }
  handleChange(e) {
    this.setState({ ctlText: e.target.value });
  }
  handleSubmit(e) {
    e.preventDefault();
    this.setState({unCtlText:this.ref.current.value});
  }
}
ReactDOM.render(
  <ComponentDemo />,
  document.getElementById('root')
);

结果如图,需要注意的是,红色框住的部分,随着受控组件值的改变而改变,而非授控组件值的显示要按submit按钮才会改变。

事件绑定使用函数bind(this),如上面的this.handleChange.bind(this),为什么要bind呢,我们来看一下

class EventBinding extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'a state value' };
  }
  render() {
    return (
      <div>
        <div><button onClick={this.handleClickBind.bind(this)}>bind</button></div>
        <div><button onClick={this.handleClick}>没有bind</button></div>
      </div>
    );
  }
  handleClickBind(){
    console.log('bind state value:',this.state.value);
    console.log('bind props value:',this.props.value);
  }
  handleClick(){
    console.log('bind state value:',this.state.value);
    console.log('bind props value:',this.props.value);
  }
}
ReactDOM.render(
  <EventBinding value="a props value" />,
  document.getElementById('root')
);

各按一次bind按钮和没有bind按钮

当按没有bind按钮时报错了,没上下文中没有this,也就没有this.state,this.props然后就报错了。所有,如果在事件处理函数中要使用到this上下关相关的东西,state,props,要 bind。为了养成习惯建议都bind不然有时忘了,找半天不知道错在哪。

React组件的生命周期

生命周期的方法有:

  • componentWillMount 在渲染前调用,在客户端也在服务端,调用一次。
  • componentDidMount : 在第一次渲染后调用,如果在这方法里调周其它方法,为避免阴塞UI展示,请使用异步调用(setTimeout, setInterval,异步ajax等),这个用得最多,一般在这个方法里面调用后端服务器获取数据进行初始化,只调用一次。
  • componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用,会调用多次。
  • shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用,会调用多次。在初始化时或者使用forceUpdate时不被调用,可以在你确认不需要更新组件时使用。
  • componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用,会调用多次。
  • componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用,会调用多次。
  • componentWillUnmount在组件从 DOM 中移除之前立刻被调用,只调用一次。

注意:componentWillMount、componentWillReceiveProps,componentWillUpdate将在react 17.0后会弃用

class LifeCycleDemo extends React.Component {
  state = {
    value: 0
  }
  componentDidMount() {
    console.log('Component DID MOUNT!')
  }
  shouldComponentUpdate(newProps, newState) {
    console.log('Component Should Update', newProps, newState)
    return true;
  }
  componentDidUpdate(prevProps, prevState) {
    console.log('Component DID UPDATE!', prevProps, prevState)
  }
  componentWillUnmount() {
    console.log('Component WILL UNMOUNT!')
  }
  render() {
    return (
      <div>
        <h3>props:{this.props.value}</h3>
        <h3>state:{this.state.value}</h3>
        <button onClick={() => this.setState({ value: this.state.value + 1 })}>修改state</button>
      </div>
    );
  }
}
class Container extends React.Component {
  state = {
    value: 1,
    removed: false
  }
  render() {
    return (
      <div>{this.state.removed ? <div>已移除</div> : <LifeCycleDemo value={this.state.value} />}
        <div><button onClick={() => this.setState({ value: this.state.value + 1 })}>修改props</button>         </div>
        <div><button onClick={() => this.setState({ removed: true })}>移除组件</button></div>
      </div>);
  }
}
ReactDOM.render(
  <Container />,
  document.getElementById('root')
);

 Component DID MOUNT!
 //初次运行没有任保操作
 //-------------------------
 Component Should Update {value: 1} {value: 1}
 Component DID UPDATE! {value: 1} {value: 0}
 //第一次按修改state
 //-------------------------
 Component Should Update {value: 1} {value: 2}
 Component DID UPDATE! {value: 1} {value: 1}
 //第二次按修改state
 //-------------------------
 Component Should Update {value: 2} {value: 2}
 Component DID UPDATE! {value: 1} {value: 2}
 //第一次按修改props
 //-------------------------
 Component Should Update {value: 3} {value: 2}
 Component DID UPDATE! {value: 2} {value: 2}
 //第二次按修改props
 //-------------------------
 Component WILL UNMOUNT!
 //按移除组件
 //-------------------------

控制台输出截图:

了解组件的生命周期,知道什么时候可以做什么,不可以做什么。

结束语

掌握上面这些,我觉得react就可以入门了,别的东西,在入门后再慢慢摸索吧,不要在门外摸了摸离开,摸了摸又离开。快速入门,然后就不要离开了。入坑吧。

原文链接:segmentfault.com

上一篇:💖CSS + JS 送学妹满屏幕小爱心
下一篇:深度:手写一个WebSocket协议 [7000字]

相关推荐

  • 🔥 Promise|async|Generator 实现&amp;原理大解析 | 9k字

    笔者刚接触async/await时,就被其暂停执行的特性吸引了,心想在没有原生API支持的情况下,await居然能挂起当前方法,实现暂停执行,我感到十分好奇。好奇心驱使我一层一层剥开有关JS异步编程的...

    7 个月前
  • 飞冰 - ICE Design Pro 使用指南

    写在前面: 目前在飞冰中,我们提供了 21 套模板(后续会持续的增加),可以在 Iceworks 的模板界面根据需求选择合适的模板进行初始化项目,然后基于区块快速搭建页面进行二次开发,减少各种环境配置...

    2 年前
  • 顺藤摸瓜🍉:用单元测试读懂 vue3 中的 provide/inject

    React Context API 提供了一种 Provider 模式,用以在组件树中的多个任意位置的组件之间共享属性,从而避免必须在多层嵌套的结构中层层传递 props。

    4 个月前
  • 页面CPU和内存占用监控可视化Chrome插件-Graph Process

    写这个插件的原因是最近要对比一下页面的 cpu 和内存占用的性能,本来是想找看看有没有什么软件能够去可视化一下当前标签页的cpu和内存占用,但是发现却找不到这种软件,mac 上有个活动监视器,但是当...

    1 年前
  • 面试题1:Promise递归实现拉取数据

    题目:请用promise递归实现拉取100条数据,每次拉取20条,结束条件为当次拉取不足20条或者已经拉取100条数据 let mockData = [ 0, 1, 2, 3, 4, ...

    6 个月前
  • 面试官要求我们手动实现 Promise.all

    情景: 最近面试,有两次被问到手动实现 Promise.all,不幸的是我都没把这题做好。因为我没有去准备这个,我不知道手动实现已有的 API 有什么意义。 但是为了防止以后还会遇到此类题,还是记录下...

    5 个月前
  • 面试官你来,130行带你手写完整Promise

    大家好,我是雷锋蜀黍。一直在某些面试宝典看到面试官要你手撸一个promise,今天天气这么好,不如我们来搞一搞。(PS:从未看过别人的实现,本文更像是记录一个思考的过程) 最终的代码完全符合Promi...

    7 个月前
  • 面试官: 聊一聊 HOC、Render props、Hooks

    在以前我们可能会看到很多文章在分析 HOC 和 render props, 但是在 2020 年 ,我们有了新欢 “hook” . 本篇文章会分析 hook , render props 和 HOC ...

    8 个月前
  • 面向未来编程(Future-Oriented Programming),建设未来 Vue 生态

    概要 Vue 的作者尤雨溪最近公布了 3.0 版本最重要的 RFC Vue Function-based API。在 React 推出 Hooks 后不久,Vue 社区也迎来了自己的组件逻辑复用机制。

    1 年前
  • 阅读Promise A+规范

    本文主要是PromiseA+规范的翻译加上个人的理解。 1 什么是Promise A promise represents the eventual result of an asynchronou...

    3 年前

官方社区

扫码加入 JavaScript 社区