React入门--第二天

  • 类组件和函数组件
  • 如何使用props和state
  • 如何绑定事件

props对应Vue中的props
state对应Vue中的data

就目前而言,返回React元素的函数就是组件
在Vue里面,一个构造选项就可以表示一个组件

函数组件

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

使用方法:<Welcome name="frank"/>

类组件

class Welcome extends React.Component{
  render(){
    return <h1>hello,{this.props.name}</h1>
  }
}

使用方法和类组件一样

<Welcome/>会被翻译成React.createElement(Welcome)
React.createElement的逻辑

  • 传入一个字符串"div",则创建一个div(虚拟DOM)
  • 传入一个函数,则会调用该函数,获取返回值
  • 传入一个类,则在类前面加个new(这会导致constructor执行),获取一个组件对象,然后调用对象的render方法,获取其返回值

试着去使用两种组件

import React from "react";
import ReactDOM from "react-dom";

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

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

  add() {
    this.setState({n:this.state.n + 1});//()里面是新的对象
  }
  render(){
    return (
      <div>
        儿子n:{this.state.n}
        <button onClick={()=>this.add()}>+1</button>
        <Grandson />
      </div>
    );
  }
}

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

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

setN是得到新的n

内部数据和外部数据的使用
外部数据props

import React from "react";
import ReactDOM from "react-dom";

function App() {
  return (
    <div>
      爸爸
      <Son messageForSon="儿子你好" />
    </div>
  );
}

class Son extends React.Component {
  render() {
    return (
      <div>
        我是儿子,我爸对我说:{this.props.messageForSon}
        <Grandson messageForGrandson="孙贼你好" />
      </div>
    );
  }
}

const Grandson = props => {
  return (
    <div>
      我是孙子,我爸对我说:{props.messageForGrandson}
    </div>
  );
};

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

内部数据state

import React from "react";
import ReactDOM from "react-dom";

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

class Son extends React.Component {
  constructor() {
    super();
    this.state = {
      n: 0
    };
  }//数据初始化
  add() {
    this.setState({n:this.state.n + 1});
  }//写数据,()里面是新对象,要改变数据就要产生新的对象
  render() {
    return (
      <div>
        儿子n:{this.state.n}//读数据
        <button onClick={()=>this.add()}>+1</button>
        <Grandson />
      </div>
    );
  }
}

const Grandson = () => {
  const [n,setN] = React.useState(0);
  return (
    <div>
      孙子n:{n}//读数据
      <button onClick={()=>setN(n+1)}>+1</button>//setN是写数据
  );
};

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

类组件中
setState里面最好写函数

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

因为setState是异步的,如果后面还有代码使用了this.state.n,那么就会出问题。
写函数就可以在函数中使用最新的this.state.n,你就是很清楚新n旧n,避免异步造成的错误

函数组件中
setN不会改变n
类组件中的setState会等一会儿改变n

总结

外部数据

  • 类组件直接读取属性this.props.xxx
  • 函数组件直接读取参数props.xxx
    内部数据
  • 类组件用this.stat读,this.setState
  • 函数组件用useState返回数组,第一项读,第二项写

类组件到的注意事项

this.state.n+=1有用吗?

  • n已经变了,没有触发UI更新
  • 调用setState才会触发UI更新(异步更新)
  • 因为React没有像Vue监听data一样监听state
    setState推荐写法
  • setState之后,state不会立马改变,立马读取state会失败
  • setState(函数)
  • React希望我们不要修改旧state(不可变数据)
  • 常用代码:setState({n:state.n+1})

函数组件注意事项

  • 也要通过setX(新值)来更新UI
  • 没有this,一律用参数和变量

Vue和React

  • Vue就是监听数据变化,然后更新UI
  • React不能修改之前的数据,只能创建一个新的数据,通过diff找到不同,局部更新UI
    在这里插入图片描述

复杂的state

如果state里面有不止有一个值,有多个的时候
类组件:

this.state = {
  n: 0,
  m: 0
};
addN(){
  this.setState({n: this.state.n + 1});
}

要改变n的值,就像上面这样写就行,但是m呢,上面并没有把没有变化的m赋值过去,
上面的写法可以看成this.setState({...this.state, n: this.state.n+1});,自动把没有变化的值赋值给新的对象

函数组件:

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

这样改变一个值也不会把另外的变为undefined
下面是不推荐写法,就会把另外的变为undefined

const Grandson = () => {
  const [state, setState] = React.useState({
    n: 0, m:0
  });

  return (
    <div>
      孙子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>
  );
};

点了n+1后m直接没了
<button onClick={() => setState({...state, n:state.n+1})}>n+1</button>就必须这样写
注意
类组件的setState会自动合并,函数组件的setState不会自动合并,并且只会自动合并第一层

this.state = {
  n: 0,
  m: 0,
  user: {
    name: "frank",
    age: 18
  }
}
render(){
  return (
    <div>
      <div>user.name: {this.state.user.name}</div>
      <div>user.age: {this.state.user.age}</div>
      <button onClick={() => this.changeUser()}>change user</div>
    </div>
  )
}
changeUser(){
  this.setState({
    user: {
      name: "jack"
    }
  });
}

上面的代码,点击change user按钮,名字被改变,然后age就没了,因为指挥自动合并第一层。
改成

changeUser(){
  this.setState({
    user: {
      ...this.state.user,
      name: "jack"
    }
  });
}

这样把之前的值赋值回来的写法即可

也可以用Object.assign()
const user = Object.assign({}, this.state.user);
上面的写法等价于
const user = {...this.state.user};
Object.assign(参数1,参数2)就是把参数2的值拷贝给参数1,然后赋值给user

函数组件则是完全不会帮你合并
全都要你自己去合并

事件绑定

有下面的写法

  • <button onClick={()=>this.addN()}>n+1</button>
    上面的这种写法最安全

  • <button onClick={this.addN}>n+1</button>
    有问题,这样会使的this.addNaddN里面的this变成window,因为在调用这个函数的时候,是用onClick调用的
    相当于button.onClick.call(null,event),this是空,所以this指向window
    addN函数里面调用this.state时就会出问题,因为值个this没有指向这个react实例,所以会出问题

  • <button onClick={this.addN.bind(this)}>n+1</button>
    用bind给this绑定为react实例,可以

下面的写法用this._add = () => this.addN()

  • <button onClick={this._addN}>n+1</button>
    就可以愉快的使用了

上面的写法多多少少有点不够优雅
看下面的
把addN变成了箭头函数

constructor(){
  this.addN = ()=>this.setState({n:this.state.n+1})
  render(){
    return <button onClick={this.addN}>n+1</button>
  }
}

就不用在constructor外面写方法了

来看看一看怎么变过去的

最开始是下面的写法

constructor(){
  this._addN = ()=> this.addN()
  render(){
    return <button onClick={this.addN}>n+1</button>
  }
}
addN() {
  this.setState({n: this.state.n + 1});
}

最终得到了一个终极写法
去掉this然后把剩下的写在constructor外面

this.addN = () => this.set....箭头函数是挂在this对象上面的
addN(){}addN: function(){}都是正常的函数写法,会挂在原型上面

看下面的写法

class Person{
  sayHi(){}
}
class Person2{
  sayHi2 = ()=>{}
}

两种不同的写法

  • 第一种的sayHi在原型上,
  • 第二种sayHi在实例本身身上
    最好用第二种写法,方法都在自己身上

this

  • 所有函数的this都是参数,由调用决定,所以可变
  • 箭头函数的this不可变,箭头函数不接受this

React VS Vue

相同点

  • 都是对视图的封装,React使用组件和类表示一个组件,Vue是通过构造选项构造一个组件
  • 都提供了createElement的XML简写,React提供的是JSX语法,Vue提供的是模板写法(语法巨多)

不同点

  • React是All in js(HTML in js)
  • Vue是js放在HTML里写(js in html)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值