初始化一个react项目:
- 全局安装react脚手架工具: npm install -g create-react-app
- 使用脚手架工具初始化react项目: create-react-app 项目名
- 启动react项目: npm start
react 与 vue的异同?
react 核心知识点:
reactRouterDom
Router
ReactComponent
render
redux:中间件。可以改变数据流
常用中间件:
- redux-logger:提供日志输出
- redux-thunk:处理异步操作
- redux-promise:处理异步操作,actionCreator的返回值是promise
优缺点: - 一个组件需要的数据,必须由父组件传递过来。
- 当一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新render,需要通过shouldComponentUpdate进行判断来阻止render。
react 函数组件与 class 组件:
函数组件:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
自定义组件:名称必须大写字母开头
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;//会渲染 Hello, Sara {name: 'Sara'}作为props传入Welcome
ReactDOM.render(
element,
document.getElementById('root')
);
// 1. 我们调用 ReactDOM.render() 函数,并传入 <Welcome name="Sara" /> 作为参数。
// 2. React 调用 Welcome 组件,并将 {name: 'Sara'} 作为 props 传入。
// 3. Welcome 组件将 <h1>Hello, Sara</h1> 元素作为返回值。
// 4. React DOM 将 DOM 高效地更新为 <h1>Hello, Sara</h1>。
class 组件:
import React from 'react'
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
组件组合/嵌套:
//自定义一个函数组件
function Comment(props) {
return (
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
);
}
//提取组件Avatar
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
function Comment(props) {
return (
<div className="UserInfo">
<Avatar user={props.author} />
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
);
}
//提取组件UserInfo
function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.author} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}
function Comment(props) {
return (
<UserInfo user={props.author />
);
}
react 的 props 不允许被更改
real DOM & Virtual DOM:
Virtual DOM/ 虚拟DOM:可以提高性能。
- 虚拟DOM是一个节点树,它将元素作为对象。元素的属性和方法作为对象的属性和方法。
- 虚拟dom相当于在 js 和 real DOM 中间加了一个缓存,利用 dom diff 算法避免了没必要的 dom 操作,从而提高性能。
具体实现:
- 用js对象结构表示DOM树结构。用这棵树构建一个real DOM,插到文档中。
- 当状态变更时,重新构造一棵新的对象树 Virtual DOM 。新的和旧的进行比较,记录差异。
- 再把差异应用到步骤1创建的real DOM上,更新视图。
diff算法:?
把树结构按照层级分解。只比较同级元素。给列表结构每个元素添加唯一的 key ,方便比较。
react性能优化方案
React性能优化
(1)重写shouldComponentUpdate来避免不必要的dom操作。
(2)使用 production 版本的react.js。
(3)使用key来帮助React识别列表中所有子组件的最小变化。
flux:数据的单向流动
reacte脚手架工具: create-react-app
react元素渲染:
react没有热更新,数据修改无法自动更新。react元素就像电影的单帧,代表某个固定时刻的UI。
会专注于差异。只更新修改的部分。
react 更新UI的方式是通过 计时器和 ReactDOM.render()。 使得每秒更新UI
import ReactDOM from 'react-dom';
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
//计时器 + ReactDOM.render() 每秒更新UI
function tick() {
const element = (
<div>
。。。
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000);
// 给UI添加一个时钟
function Clock(props) {
return (
<div>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
以上的时钟只能在render的那一刻获取到那一刻的时间。怎样让这个时钟实现每秒更新呢?
向组件中添加 State ,是当前组件私有的属性,完全受控于当前组件。 this.setState
import React from 'react'
import ReactDOM from 'react-dom';
class Clock extends React.Component {//封装时钟的外观组件
constructor(props) {
super(props);// 通过 super 将 props 传递到父类的构造函数中
this.state = {date: new Date()};//构造函数是唯一可以给 this.state 赋值的地方
}
componentDidMount() {// 组件挂载 。在组件完全渲染后执行,类型mounted
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() { // 组件要被删除时,卸载 unmount
clearInterval(this.timerID);
}
tick() {
this.setState({// state不要直接修改,使用setState()去修改 , state 改变会重新调用render()
date: new Date()
});
}
render() {
return (// JSX 用法。JavaScript + xml
<div>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
State & 生命周期: componentDidMount , componentWillUnmount
-
- state不要直接修改,使用setState()去修改
-
- 构造函数是唯一可以给 this.state 赋值的地方
this.state.m = 'aa';// wrong
this.setState({ m: 'aa' });// right
-
- state 的更新可能是异步的,所以不要依赖 this.props 或者 this.state 的值来更新状态。让 setState()接收一个函数,state 作为第一个参数,props 作为第二参数
this.setState((state, props) => ({// 为了解决state存在异步更新情况,无法通过接收对象作为参数来处理 props 和 state 的问题,解决方法是接收一个函数作为参数:(state, props) => ({})
counter: state.counter + props.increment
}));
-
- State 的更新会被合并:
import React from 'react'
import ReactDOM from 'react-dom';
class Com extends React.Component{
constructor(props) {
super(props);
this.state = {
a:[],
b:{}
}
}
componentDidMount() {
fetchPosts().then(response => {
this.setState({
a: response.posts
});
});
fetchComments().then(response => {
this.setState({
b: response.comments
});
});
}
}
ReactDOM.render(
<Com />,
document.getElementById('root')
);
-
- state 数据是向下流动的 / 单向数据流 :因为 state 属于当前组件的私有属性,其他组件无法访问。但 state 可以作为 props 向下传递给子组件
<Comp mydate={this.state.date} />
function Comp(props) {
return <h2>It is {props.mydate.toLocaleTimeString()}.</h2>;
}
-
- state状态提升。 将内容提升到共有的父组件中,通过props向下传递。通过 this.props.func(e.target.value); 去父组件真实处理业务逻辑
事件处理:
- 事件命名采用小驼峰,camlCase
- 使用JSX时需要传入一个函数参数作为事件处理函数
// react
<button onClick={activateLasers}> Activate Lasers </button>
- 无法通过
return false
阻止默认行为,需要使用preventDefault
function Form() {//class Form extends React.Component{}
function mySubmit(e) {
e.preventDefault();
console.log('You clicked submit.');
}
return (
<form onSubmit={mySubmit}>
<button type="submit">Submit</button>
</form>
);
}
- 注意 this 的绑定,class 的方法默认不会绑定this。
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 为了在回调中使用 `this`,使用 bind()
this.handleClick = this.handleClick.bind(this);
}
handleClick() {// 使用箭头函数写法也可以使得 click 事件能访问到 class 的 this。 handleClick = () => {}
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {// onClick={ () => this.handleClick() } 直接在元素上通过箭头函数写法绑定函数也可以访问到 this
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
- 给事件处理函数传递参数:
<button onClick={ (e) => this.deleteRow(id, e) }>Delete Row</button>
<button onClick={ this.deleteRow.bind(this, id) }>Delete Row</button>
条件渲染
与运算符:true && expression 总是会返回 expression, 而 false && expression 总是会返回 false , 0 && expression 会返回 0
组合 vs 继承:
// 包含关系
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
}
/>
);
}
// 特例关系
function Dialog(props) {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
{props.title}
</h1>
<p className="Dialog-message">
{props.message}
</p>
</FancyBorder>
);
}
function WelcomeDialog() {
return (
<Dialog
title="Welcome"
message="Thank you for visiting our spacecraft!" />
);
}
组件可以接受任意 props,包括基本数据类型,React 元素以及函数。props 不能被修改。