学习React官方文档(一)

348 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天

笔者是今年应届毕业生,由于春招找到的单位的项目是以React为前端框架,遂进行React的学习,以下是根据自己阅读官方文档以及学习Dell老师的一些React笔记,自己随手记录,也供大家参考

JSX语法

JSX语法是是一个JavaScript 的语法扩展,它本身没有太多的定义,也没更多的标准~JSX通过类似XML的描述方式,描写函数对象

const name = 'Samba'
const element = <h1> Hello ,{name}</h1>

JSX语法将Javascript函数放在{}中

元素渲染

首先使用JSX语法创建一个React元素

const element = <h1>Hello,world</h1>

假设在HTML文件某处有一个div,将其称为“根” DOM 节点,并且该节点内的所有内容都将由 React DOM 管理,如下

<div id='root'><div>

将一个React元素(即用JSX语法创建的元素)渲染到DOM节点。将root和element传入ReactDOM.createRoot(),页面将会显示Hello

const element = <h1>Hello</h1>
const root = ReactDOM.cereateRoot(
	document.getElementByid('root')
);
root.render(element)

组件


在React中定义一个组件的方法如下,其中props是properties的简写,代表外部传入该组件的参数,并且props不能被修改。

class 组件名 extends React.Component {

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

}

渲染组件

React元素可以是html标签,也可以是用户自定义的组件

const element = <div />     //这是一个React元素

const element = <Welcom name="Samba" />   //这也是一个React元素

例如:下面这段代码就会在页面上渲染“你好,Samba”

function Welcom(props) {
	return <h1>你好,{props.name}</h1>
}

const element = <Welcome name='Samba' />;
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);

以上这段代码执行思路:

1、我们调用root.render()函数将名为element的React元素传入DOM根节点,并且传入name=“Samba”作为参数

2、React调用Welcome组件,并将name=“Samba”作为props传入,因为props是一个对象,所以传入的实际的传入形式是{name: ‘Samba’}

3、Welcome 组件将<h1>你好,{props.name}</h1>元素作为返回值

4、React DOM将DOM更新为<h1>你好,Samba</h1>

组件的组合

一个组件可以在其返回值中引用其他组件,达到组件复用的效果

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

function App() {
  return (
    <div>
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Welcome name="Edite" />
    </div>
  );
}

封装一个可复用的Clock组件

用JavaScript函数义一个时钟组件

function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

用class定义一个组件(class是es6语法,可以用来定义一个类)

class Clock extends React.Component {
	render() {
		return (
			<div>
				<h1>Hello,world</h1>
				<h2>It is {this.props.data.toLocaleTimeString()}.</h2>
			</div>
		);
	}
}

function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}

将函数组件转换成class组件

1、创建一个同名的ES6 class ,并且继承于React.Component

2、添加一个空的render()方法

3、将函数体移动到render()方法之中

4、在render()方法中使用this.props替换props

5、删除剩余的空函数声明

现在Clock组件被定义为class,而不是函数,每次组件更新时,render方法都会被调用

State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。

接下来,将render()方法中的this.props.data替换成this.state.data

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

render() {
	return (
		<div>
			<h1>Hello,world</h1>
			<h2>It is {this.state.date.toLocaleTimeString()}</h2>
		</div>
	 );
	}
}

ReactDOM.render(
	<Clock />
	document.fetElementById('root)
);

这样就完成了一个Clock组件的封装,我们也可以直接拿来用

生命周期方法

当组件被挂载或者卸载时会自动执行的方法,就叫做生命周期方法

componentDidMount()方法,它会在组件已经被渲染到 DOM 中后运行

再比如componentWillUnmount()方法,组件卸载及销毁之前直接调用,在此方法中执行必要的清理操作

接下来,将生命周期方法添加到Clock组件中

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

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

我们使用this.setState()来时刻更新组件中的 state,上面代码的执行过程

1、组件被传给root.render(),并且会调用Clock组件的构造函数,构建并初始化一个对象,并且this.state的初始化值为当前时间的对象,state的值会在之后更新

2、React调用组件的render()方法,也就是在页面上显示什么。

3、当Clock组件的输出被插入到DOM后,React会调用componentDidMount()生命周期方法,这个方法中,Clock组件向浏览器设置一个计时器每秒钟调用一次组件的tick()方法。

4、浏览器每秒都调用一次tick方法,在这个方法中,Clock组件通过调用setState()方法来进进行UI更新。React通过setState方法知道state改变之后,重新调用render方法来确定页面上显示什么。这一次,Clock组件中render()方法的this.state.date发生了改变,这样就会渲染更新过的时间,即React会相应的更新DOM

5、当Clock组件从DOM中移除,React会调用componentWillUnmount()生命周期方法,这样计时器就停止。

关于setState的使用要注意以下几点

1、不要直接修改state

this.setState.comment = 'Hello'. //错误
this.setState({comment: 'Hello'}). //正确

2、state更新可能是异步的,当在事件处理函数内部,setState是异步的,比如Parent和Child在同一个click事件中都调用setState,这样就可以确保Child不会被重新渲染两次。所以setState要传递一个函数,以保证state的值是最新的

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

3、当调用setState()的时候,React会把提供的对象更新并合并到当前state,意思就是可以用setState更新state的值

constructor(props) {
	super(props)
		this.state = {
				posts: [],
				comments: []
		};
}

事件处理

React中事件的命名采用小驼峰式(camelCase)如:onClick

使用JSX时需要传入一个函数作为事件处理函数,即发生这个事件后的下一步操作。

下面代码展示的是在组件中的事件处理

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

handleClick() {
	this.setState(prevState => ({
		isTogglenOn: !preState.isToggleOn
	}));
}

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

Javascript中,class方法默认不会绑定this,如果忘记绑定this.handleClick,当调用这个函数时,this的值为undefind。如果觉得bind麻烦,可以使用以下两种方式

方法一:使用public class fields方法

class Button extends React.Component {
	constructor(props) {
		super(props);
		this.state = {***}
	}

	handleClick = () => {
			console.log('this is:', this)
	}

render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

方法二:在回调中使用箭头函数:

class Button extend React.Component {
	handleClick = () => {
			console.log('this is:', this)
        }

	render() {
		return( {
			<button onClick={() => this.handleClick()}>
				Click me
			<button/>
		);
	}
}