一起养成写作习惯!这是我参与「掘金日新计划 · 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/>
);
}
}