React组件入门

61 阅读3分钟

在React中,一个返回React元素的函数就是组件

在Vue中,一个构造选项就可以表示一个组件

const div = React.createElement('div',...)

这是一个React元素 d小写

const Div =()=>React.createElement('div',...)

这是一个React组件 D大写

两种组件

函数组件


function Welcome(props){

return <h1>Hello,{props.name}</h1>

}

//使用方法:<Welcome name='Origami' />

类组件


class Welcome extends React.Component{

render(){

return <h1>Hello,{this.props.name}</h1>

}

}

//使用方法:<Welcome name='Origami' />

class组件需要写一个render函数用于渲染视图。

此处的会被翻译成React.createElement(Welcome)

React.createElement的逻辑

  • 如果传入一个字符串'div',则会创建一个div

  • 如果传入一个函数,则会调用这个函数,获取它的返回值

  • 如果传入一个类,则在这个类前面加一个new(会执行constructor),获取一个组件对象,然后调用对现哥render方法,获取返回值

两种写法的示例


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);

image.png

Props和State

使用外部数据props


import React from "react";

import ReactDOM from "react-dom";

import "./styles.css";

function App() {

return (

<div className="App">

爸爸

<Son messageForSon="儿子你好" />

</div>

);

}

class Son extends React.Component {

render() {

return (

<div className="Son">

我是儿子,我爸对我说「{this.props.messageForSon}」

<Grandson messageForGrandson="孙子你好" />

</div>

);

}

}

const Grandson = props => {

return (

<div className="Grandson">

我是孙子,我爸对我说「{props.messageForGrandson}」

</div>

);

};

const rootElement = document.getElementById("root");

ReactDOM.render(<App />, rootElement);

image.png

通过在标签中写xxx="yyy"

类组件直接读取属性this.props.xxx即可读取yyy

函数组件直接读取参数props.xxx即可读取yyy

使用内部数据state


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);

依然是这一段代码

类组件this.state读,this.setState

如写:

add() {

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

}

读:儿子 n:{this.state.n}

另外初始化时必须在constructor内写super

这里add()不能用this.state.n+=1是因为虽然n已经改变了,但是UI没有同步更新,需要调用setState才会触发UI的更新,但是这是一个异步的更新,因为React没`有像Vue监听data那样监听state

所以诞生了更好的写法那就是


this.setState((state)=>{

return {n:this.state.n+1}

})

即setState(函数)

此外this.setState(this.state)并不被推荐,因为React并不希望我们直接修改旧对象,更希望生成一个新的对象。比如setState({n:this.state.n+1})

函数组件useState返回数组,第一项读,第二项写

声明时const [n, setN] = React.useState(0)useState(0)的0表示初始值

setN(n+1)是写,但是永远不会改变n,而是产生一个新的n


复杂state

总结:

类组件的setState会自动合并第一层属性,但不会合并第二层属性。

使用Object.assign或者...操作符把之前的内容写进来,在修改局部,否则会出现置空现象。

函数组件则不会自动合并任何属性,如果要合并只能通过...操作符


事件绑定

<button onClick={() => this.add()}>+1</button>这样写最为稳定

<button onClick={this.add.bind(this)}>+1</button>这样写返回了一个绑定当前this的心函数,是可以的

<button onClick={this.add}>+1</button>这样会让this.add里面的this变成window,是有问题的

最好的写法


add = () => {

this.setState((state)=>{

return {n:this.state.n+1}

})

};

render() {

return (

<div className="Son">

儿子 n: {this.state.n}

<button onClick={this.add}>n+1</button>

定义时用箭头函数,调用时直接写函数名。

Vue和React在编程模型上的区别

Vue编程

一个对象对应一个虚拟DOM,当对象的属性改变时,把属性相关的DOM节点全部更新

React编程模型

一个对象对应一个虚拟DOM,另一个对象对应两一个虚拟DOM,对比两个虚拟DOM,通过DOM diff找不同实现局部更新UI。