React
以下只是我对react的学习和阅读react文档之后的一个笔记,如果有什么写的不对的地方,可以的话麻烦请告诉我一下,谢谢。
(这里只提到了关于react类形式用法,以后可能也会写一些关于hook的总结)
react项目的组成
react 的项目有两种实现形式,一种是类形式(class组件),一种是hook形式(函数组件)
ReactDOM.render方法
ReactDOM.render 方法传入两个参数:第一个参数是要渲染的内容,第二个参数是要插入的节点
ReactDOM.render(
<h1>Hello World</h1>,
document.getElementById('root')
);
JSX语法
JSX语法指的是javascript+XML语法(简单理解为HTML)
const world = 'world!';
ReactDOM.render(
<h1>Hello {world}</h1>,
document.getElementById('root')
);
其中{}表示javascript的表达式,搭配html的标签实现页面内容的编写
编写class组件
每一个class组件都会导出一个类,继承的react下的component类,并且定义一个render函数,返回一个节点
// App 组件
import React from 'react';
export default class App extends React.Component{
render() {
return(
<h1>
Hello World
</h1>
)
}
}
使用组件(以标签的形式使用组件)
import App from './app';
ReactDOM.render(
<App/>,
document.getElementById('root')
);
state状态
react组件中储值的方式有两种:state和props。其中state是组件自身维护的状态,而props则是常用于组件之间复用组件的数据传递,react组件不允许自身修改props
// 定义state
import React from 'react';
export default class App extends React.Component {
constructor() {
super();
this.state = {
title: 'react props'
};
}
// 通过this.state调用state状态值
render() {
return (
<div>
<h1>{this.state.title}</h1>
<button onClick={this.changeTitle}>修改标题</button>
</div>
);
}
// 修改state状态
changeTitle = () => {
this.setState({
title: 'change title'
})
}
}
this指向问题
在上面的changTitle事件声明中,使用了箭头函数,是为了保证函数执行时this的指向为react组件自身。也可以使用下面的bind写法
import React from 'react';
export default class App extends React.Component {
constructor() {
super();
this.state = {
title: 'react props'
};
}
// 通过this.state调用state状态值
render() {
return (
<div>
<h1>{this.state.title}</h1>
<button onClick={this.changeTitle.bind(this)}>修改标题</button>
</div>
);
}
// 修改state状态
changeTitle() {
this.setState({
title: 'change title'
})
}
}
在使用或声明react组件自身的属性和方法时都要注意this指向问题
组件之间的通讯传递
组件可以通过props属性来传递数据
// PropsDemo 组件
import React from 'react';
export default class PropsDemo extends React.Component {
render() {
return(
<div>
<h1>{this.props.title}</h1>
</div>
)
}
}
// App 组件
import React from 'react';
import PropsDemo from "./propsDemo";
export default class App extends React.Component{
constructor() {
super();
this.state = {
title: 'react props'
};
}
render() {
return(
<div>
<PropsDemo title={this.state.title}/>
</div>
)
}
}
上面的代码中,通过props属性从父组件(App)传递给子组件(PropsDemo)
props的只读性:react组件自身是不能修改props属性的值
当需要通过子组件向父组件传递值时,我们可以通过事件回传的方式实现
// PropsDemo组件
import React from 'react';
export default class PropsDemo extends React.Component {
changeTitleHandler = () => {
this.props.changeTitleHandler('react props title after changed');
};
render() {
return (
<div>
<h1>{this.props.title}</h1>
<button onClick={this.changeTitleHandler}>修改标题</button>
</div>
);
}
}
// App组件
import React from 'react';
import PropsDemo from "./propsDemo";
export default class App extends React.Component {
constructor() {
super();
this.state = {
title: 'react props'
};
}
changeTitle = (title) => {
this.setState({
title: title
});
};
render() {
return (
<div>
<PropsDemo title={this.state.title} changeTitleHandler={this.changeTitle}/>
</div>
);
}
}
生命周期
生命周期方法是react组件运行过程中特定的阶段执行的方法,我们可以重写这些方法,实现项目的开发需求
在react的官方文档中将这些方法分为两类:常用和罕见。这里先说常用的
render:render方法是react组件中必须实现的方法。这个方法是一个纯函数方法(不做任何状态的改变,浏览器交互等),根据state和props的变化返回渲染元素
constructor:构造函数主要有两种用途,初始化state和为事件绑定实例
componentDidMount:在组件挂载完之后就会调用componentDidMount方法,可以在这里实例化请求和添加订阅
componentDidUpdate:当组件更新时调用该方法,可以对state和props做改变前后的对比。该方法接受三个参数,第一个是prevProps,第二个是prevState,第三个是snapshot(不常用)
componentWillUnmount:当组件即将被卸载时,该方法会被调用。如果组件中有已添加的订阅,可以在这里取消订阅
事件处理
在react的事件绑定中,传递的不是一个字符串,而是一个事件处理器
<div>
<PropsDemo title={this.state.title} changeTitleHandler={this.changeTitle}/>
</div>
在阻止默认事件的时候,不能通过返回false方式,只能显式的时候preventDefault
function changeTitle(e) {
e.preventDefault();
}
在绑定事件中,可以通过箭头函数和bind的方法来指定实例
// bind方式
class x extends React.Component {
constructor() {
super();
this,handler = this.handler.bind(this);
}
handler() {
console.log(this);
}
}
// 箭头函数
class x extends React.Component {
handler = () => {
console.log(this);
}
}
在react的事件绑定中,如果在绑定时直接加()是会在渲染完成之后直接触发的,并不会按照我们设计好的情境下触发。当我们需要向事件处理器传递参数时,我们也可以使用箭头函数和bind的形式
<button onClick={ () => this.print('the text') }></button>
<button onClick={ this.print.bind(this, 'the text') }></button>
条件渲染
在react组件中,使用条件渲染可以依据不同的状态值渲染不同的组件内容
// IfDeo 组件
import React from 'react';
export default class IfDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
isLogin: false
}
}
render() {
return (
<div>
{
this.state.isLogin
? <h3>已登录</h3>
: <h3>未登录</h3>
}
</div>
)
}
}
如果你在某个状态下不想渲染某个组件,可以让render直接返回null
列表渲染
当我们想要渲染多个相同的组件或列表的时候,使用列表渲染会很简单
// ListDemo 组件
import React from "react";
export default class ListDemo extends React.Component {
render() {
const list = [1, 2, 3, 4, 5];
return (
<ul>
{
list.map((val, index) => <li key={index}>{val}</li> )
}
</ul>
)
}
}
react要求我们在使用列表渲染的时候需要指定key值,兄弟节点之间的key值是唯一的。在这里我们指定索引为key。管文文档中提到,如果项目列表数据可能发生改变的话,建议不要使用索引。如果数据中有id或者其他唯一的值,我们可以指定该值为key。
文档中提到了key的作用是帮助react识别哪些元素发生了改变了,从而快速的定位和更新dom树深入解析为什么 key 是必须的
表单组件
在react中表单组件分为两种:受控组件和非受控组件。
在html开发中,我们经常使用操作dom的方法来对表单的值进行处理。而在react中我们可以通过state来保存表单组件的值,这就是受控组件。
而不是通过state来操作的组件,则是非受控组件。
受控组件
// FormDemo 组件
import React from "react";
export default class App extends React.Component {
constructor() {
super();
this.state = {};
this.changeHandler = this.changeHandler.bind(this);
}
changeHandler(e) {
this.this.setState({
username: e.target.value
})
}
render() {
return (
<form>
<label>
用户名
<input type="text" name='username' onChange={ this.changeHandler }/>
</label>
<button onClick={ this.printHandler }>打印</button>
</form>
)
}
}
上面的代码中,input的值在改变的之后通过绑定的事件将值保存到了state上。在react中,大部分的表单组件都是以这样的形式来保存。例如textarea,checkbox,select
import React from "react";
export default class FormDemo extends React.Component {
constructor() {
super();
this.state = {
fruit: 'apple',
isGoing: true,
isFast: false
};
this.changeHandler = this.changeHandler.bind(this);
this.printHandler = this.printHandler.bind(this);
}
changeHandler(e) {
const name = e.target.name;
const value = (name === 'isGoing' || name === 'isFast') ? e.target.checked : e.target.value;
this.setState({
[name]: value
})
}
printHandler(e) {
e.preventDefault();
console.log(this.state);
}
render() {
return (
<form>
<label>
用户名
<input type="text" name='username' onChange={ this.changeHandler }/>
</label>
<label>
密码
<input type="text" name='password' onChange={ this.changeHandler }/>
</label>
<select name="fruit" value={ this.state.fruit } onChange={ this.changeHandler }>
<option value="apple">苹果</option>
<option value="banana">香蕉</option>
<option value="watermelon">西瓜</option>
</select>
<textarea name="content" value={ this.state.content } onChange={ this.changeHandler }></textarea>
<label>
快速
<input name="isFast" type="checkbox" checked={ this.state.isFast } onChange={ this.changeHandler }/>
</label>
<label>
前进
<input name="isGoing" type="checkbox" checked={ this.state.isGoing } onChange={ this.changeHandler }/>
</label>
<div>
<label>
1
<input type="radio" name="nums" value='1' onChange={ this.changeHandler } />
</label>
<label>
2
<input type="radio" name="nums" value='2' onChange={ this.changeHandler } />
</label>
<label>
3
<input type="radio" name="nums" value='3' onChange={ this.changeHandler } />
</label>
</div>
<button onClick={ this.printHandler }>打印</button>
</form>
)
}
}
非受控组件
而当使用input[file]接收文件时,就无法使用state来保存,需要通过非受控组件来获取文件
非受控组件实际上就是就是将数据保存在dom节点上,通过操作dom节点的方式来获取数据。而在react中想要操作dom,可以通过ref
// RefDemo 组件
import React from "react";
export default class RefDemo extends React.Component {
constructor() {
super();
this.username = React.createRef();
this.printHandler = this.printHandler.bind(this);
}
printHandler(e) {
e.preventDefault();
console.log(this.username.current.value);
}
render() {
return (
<form>
<input type="text" ref={ this.username }/>
<button onClick={ this.printHandler }>打印</button>
</form>
);
}
}