- 要去https://nodejs.org/zh-cn/安装node.js(工程化项目创建项目和启动项目依赖于node.js)
node -v 查看版本号
- 安装node.js自带的包管理工具
npm npm install webpack -g
或者npm install yarn -g
- 安装node.js自带的包管理工具
npm -v 查看版本号
- 全局安装脚手架
npm install -g create-react-app
或者yarn add create-react-app -g
- 全局安装脚手架
create-react-app --version 查看版本号
- 在命令行里输入
create-react-app demo
(这里的demo指的是你项目的名字),然后等待安装完成
完成之后npm start
或者yarn start
启动项目
- 在命令行里输入
项目目录
README.md 项目说明文档
node_modules 依赖文件夹
package.json npm依赖
public 静态资源
-- favicon.ico
-- index.html
src 源码
-- index.js 入口js
-- App.js 入口组件
这样的话一个react的项目就创建完了
react基础知识
-
1.理解react和react-dom两个库
react
只做逻辑层
react-dom
做渲染层,去渲染实际的DOM -
2.剖析JSX的实质
JSX语法即JS和html的混合体,实际的核心逻辑就是用js去实现的
JSX的实质就是React.createElement
的调用
JSX写法
class HelloMessage extends React.Component {
render() {
return (
<div>
Hello {this.props.name}
</div>
);
}
}
ReactDOM.render(
<HelloMessage name="Taylor" />,
document.getElementById('hello-example')
);
React里的写法
class HelloMessage extends React.Component {
render() {
return React.createElement(
"div",
null,
"Hello ",
this.props.name
);
}
}
ReactDOM.render(React.createElement(HelloMessage, { name: "Taylor" }), document.getElementById('hello-example'));
代码1
import React, { Component } from "react";
export default class App extends Component {
render() {
return (
<div></div>
);
}
}
代码2
import React from "react";
export default class App extends React.Component {
render() {
return (
<div> </div>
);
}
}
代码1和代码2写法不一样,效果一样
- 讲解state变量渲染和setState修改数据
在组件里面我们通过{}
在JSX
渲染变量
如果数据需要修改,并且需要页面同时响应改变,那就需要把变量放在state
里面,同时使用setState
修改
初始化状态state
// 初始化状态
this.state = {
count: 0
};
更新状态使用setState
,不能直接this.state.count=xxx
// 更新状态
this.setState({
count: this.state.count + 1
});
注意事项
setState
是异步的,底层设计同一个生命周期会批量操作更新state
setState
第二个参数是一个可选参数,传入一个回调函数可以获取到最新的state
this.setState({
value:this.state.value + 1
},()=>{
console.log(this.state.value)
})
当修改的state
依赖上一次修改的state
的值时,可使用以下这种方法修改
this.setState((prevState, prevProps)=>({
//prevState:上一次修改的状态state
//prevProps:上一次修改的属性props
count: prevState.count + 1
}), () => {
//这里可以获取到最新的state
console.log(this.state.count);
});
- props属性传递
父组件向子组件传递属性利用props接收
<PropsDemo title="父组件信息"></PropsDemo>
子组件使用
//class组件使用
<h1>{this.props.title}</h1>
//函数型组件使用
function xxx(props){
return <h1>{props.title}</h1>
}
//解构赋值写法
function xxx({title}){
return <h1>{title}</h1>
}
- 5.条件渲染与数据循环
三目表达式写法
{ this.state.isShow?<p>{this.props.title}</p>:null}
map映射
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
goods: [
{ title: 'html+css基础⼊⻔', price: 19.8 },
{ title: 'js零基础阶级', price: 29.8 },
{ title: 'vue基础⼊⻔', price: 19.8 },
{ title: 'vue电商单⻚⾯项⽬实战', price: 39.8 },
{ title: 'react零基础进阶单⻚⾯项⽬实战', price: 59.8 },
]
}
}
render() {
return (
<div className="App">
{console.log('react项目-rcc创建')}
<ul>
{this.state.goods.map((item, index) => (
<li key={item.title}>
<p>科目 : {item.title}</p>
<p>价格 : {item.price}</p>
</li>
))}
</ul>
</div>
)
}
}
- 6.事件的绑定
6.1.箭头函数写法(最常用)
isShow = () => {
//做一些操作
this.setState({
//设置state里的值
});
};
<button onClick={this.isShow}>显示标题</button>
6.2.直接使用箭头函数返回一个函数
isShow(){
//做一些操作
this.setState({
//设置state里的值
});
};
<button onClick={() => this.isShow()}>显示标题</button>
- 7.样式编写
行内样式
<img style={{ width: "100px",height:"100px" }} />
添加类名
<img className="img" />
添加属性
// 先引入
import logo from './logo.png'
<img src={logo} />
- 8.双向数据绑定
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
defaultVal: '我是默认值'
}
}
handleChange = (e) => {
this.setState({
defaultVal: e.target.value
})
}
render() {
return (
<div className="App">
<input type="text" onChange={this.handleChange} />
<p>{this.state.defaultVal}</p>
</div>
)
}
}
React UI库的引入
- 9.引入antd库
在命令行输入以下命令可以安装antd库
npm install antd --save
按需加载antd配置,需要对create-react-app的默认配置进行自定义
- 更改启动插件。引入creat-app-rewired并修改package.json里的启动配置,由于新的react-app-rewired@2.x版本的关系,还需要安装customize-cra
- 输入
yarn add react-app-rewired customize-cra
(npm install yarn -g 进行安装yarn) - 更改package.json文件
"scripts": {
// "start": "react-scripts start",
"start": "react-app-rewired start",
// "build": "react-scripts build",
"build": "react-app-rewired build",
//"test": "react-scripts test",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
},
- 然后在根目录创建一个config-overrides.js文件,用于修改默认配置
- 安装babel-plugin-import插件
yarn add babel-plugin-import
- 修改config-overrides.js文件内容
const { override, fixBabelImports } = require('customize-cra');
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
}),
);
注:
按需加载之后不需要引入antd.css
配置完按需加载之后就可以直接使用antd官网里面的例子进行引入组件
// 例如
import { Button } from 'antd';
到这里按需加载ant-design就配置完成了,如果没有显示或者报错可以关闭控制台重启项目
性能优化
- 10.性能优化之PureComponent
PureComponent
是内部定制了shouldComponentUpdate
生命周期的Component,它重写了一个方法来替换shouldComponentUpdate生命周期方法
平常开发过程中设计组件能使用PureComponent的地方都尽量使用
想要使用PureComponent特性要记住两个小原则:
- 确保数据类型是值类型
- 如果是引用类型,确保地址不变,同时不应当有深层次数据变化
使⽤PureComponent可以省去shouldComponentUpdate⽣命周期的代码,代码会简单很多
示例代码
import React, { Component ,PureComponent} from 'react'
import { Button } from 'antd';
// 使用PureComponent来做优化
class Title extends PureComponent {
// 使用shouldComponentUpdate()生命周期来做优化
// shouldComponentUpdate(nextProps){
// return nextProps.title !== this.props.title
// }
render() {
console.log('我是title组件')
return (
<div>
标题 : {this.props.title}
</div>
)
}
}
class Count extends Component {
render() {
console.log('我是count组件')
return (
<div> 条数 : {this.props.count} </div>
)
}
}
export default class App extends Component {
constructor(props){
super(props)
this.state={
title:'时代周报',
count:0
}
}
handelAdd=()=>{
this.setState({
count:this.state.count+1
})
}
render() {
return (
<div>
<Button type="primary" onClick={this.handelAdd}>按钮</Button>
<Title title={this.state.title}></Title>
<Count count={this.state.count}></Count>
</div>
)
}
}
- 11.性能优化之React.memo
React.memo是⼀个⾼阶组件的写法
React.memo让函数组件也拥有了PureComponent的功能
使⽤例⼦如下:
const Title = React.memo((props)=>{
console.log('我是title组件')
return(
<div>
标题 : {props.title}
</div>
)
})
- 12.三种优化的方法
1.使用shouldComponentUpdate()
生命周期
class Title extends Component {
shouldComponentUpdate(nextProps){
return nextProps.title !== this.props.title
}
render() {
console.log('我是title组件')
return (
<div> 标题 : {this.props.title}</div>
)
}
}
2.使用PureComponent
// 首先要引入PureComponent
import React, { Component ,PureComponent} from 'react'
class Title extends PureComponent {
render() {
console.log('我是title组件')
return (
<div>
标题 : {this.props.title}
</div>
)
}
}
3.使用React.memo
// 使用React.memo代替以上Title代码,让函数式组件也拥有PureComponent的功能
const Title = React.memo((props)=>{
console.log('我是title组件')
return(
<div>
标题 : {props.title}
</div>
)
})
- 13.React高级使用之组件复合写法
组件复合:类似于Vue中的插槽,复用组件
react官方: 任何一个能用组件继承实现的,都能用组件复合实现
import React from 'react'
import {Button} from 'antd'
function Dialog(props) {
return (
<div style={{ border: `2px solid ${props.color ||"green"}` }}>
{props.children} {/* 相当于vue里面的匿名插槽 */}
{props.btn} {/* 相当于vue里面的具名插槽 */}
</div>
)
}
export default function composition() {
const btn = (
<Button onClick={() => alert('具名插槽')}>Button</Button>
)
return (
<div>
<h1>组件复合的写法</h1>
<Dialog color="pink" btn={btn}>
{/* 可以放任意想放的内容 */}
<p>匿名插槽</p>
<p>复合的标签</p>
</Dialog>
</div>
)
}
高阶组件
- 14.高阶组件
高阶组件:HOC,为了提高组件的复用率,抽离出具有相同逻辑/展示的组件;
高阶组件其实是一个函数,接收一个组件,返回一个新的组件,这个新组件可以对属性进行包装,也可以重写部分生命周期;
简单使用
HOCompt.js
import React, { Component } from 'react'
//编写一个高阶组件,传递一个组件进去,返回一个新的组件
const withLearnReact = (Compt) => {
const NewCompt = (props) => {
return <Compt {...props} name="高阶组件" />
}
return NewCompt
}
class HOC extends Component {
render() {
return (
<div>
<p>高阶组件写法</p>
<p>title : {this.props.title}</p>
<p>姓名 : {this.props.name}</p>
</div>
)
}
}
export default withLearnReact(HOC)
App.js
import React, { Component } from 'react'
import HOCompt from './HOCompt'
export default class App extends Component {
render() {
return (
<div>
<HOCompt title="App use"></HOCompt>
</div>
)
}
}
- 15.链式调用
- 如果是纯展示的组件,则返回一个函数式组件;如果需要重写生命周期,则返回类组件;
- 在 HOCompt 组件中,新添加一个返回类组件的函数,并重写类组件的生命周期方法;
/*
1.创建一个高阶组件 const
2.传入一个参数
3.创建一个class组件
4.把传入的属性传出去 用{...props}
*/
//编写一个高阶组件,重写生命周期,注意:重写生命周期需要class组件
const withLifeCycle = (Compt) =>{
class NewCompt extends Component{
//重写组件生命周期
componentDidMount(){
console.log('重写componentDidMount生命周期')
}
render(){
return <Compt {...this.props}></Compt>
}
}
return NewCompt
}
// 链式调用写法
// withLearnReact(HOC) 返回一个函数式组件,传递了 name 和 title ,该组件作为 withLifeCycle() 的参数,返回一个重写了生命周期方法的类组件。
export default withLifeCycle(withLearnReact(HOC))
- 16.高阶组件装饰器写法(代替链式调用)
- ES7中出现的装饰器语法,来处理高阶组件链式调用逻辑比较绕且不易理解
- 安装装饰器语法的babel编译插件
npm install --save-dev @babel/plugin-proposal-decorators
然后找到之前配置的config-overrides.js
里面再写入配置装饰器写法, 此时的文件内容是
const { override, fixBabelImports, addBabelPlugins } = require('customize-cra');
module.exports = override(
//配置antd按需加载
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
}),
//配置支持高阶组件装饰器
addBabelPlugins(
[
'@babel/plugin-proposal-decorators',
{
legacy: true
}
]
),
);
配置完之后,就可以把链式调用去掉,直接暴露HOC
// export default withLifeCycle(withLearnReact(HOC))
export default HOC
然后需要在高阶组件声明之后依次写入以下代码,就可以代替链式调用
@withLearnReact
@withLifeCycle
注
: 如果现在项目报错,可以重新npm install
一下,然后再启动项目
组件通信之上下文(context)
- 17.组件通信之上下文(context)
- 当父组件与孙组件通信时,涉及到中间组件传递
props
,当中间组件很多时,可能破坏props
的数据完整性; -
Context
的作用就是实现多级组件之间的通信,让所有后代组件共享同一个父组件的数据,避免传递props
-
Context
有两个角色:Provider(数据提供)
、Consumer(数据读取)
,Vue也借鉴了这种方式,分别对应provider
、inject
示例代码
import React, { Component } from 'react'
//数据
let store = {
name: '杜兰特',
from: '布鲁克林篮网'
}
//创建上下文
const Context = React.createContext()
const { Provider, Consumer } = Context
class Data extends Component {
render() {
return (
<Consumer>
{store => {
return (
<div>
<p>姓名 : {store.name}</p>
<p>来自 : {store.from}</p>
</div>
)
}}
</Consumer>
)
}
}
function Info(){
return(
<Data></Data>
)
}
function ToolBar() {
return (
<Info></Info>
)
}
export default class Context2 extends Component {
render() {
return (
<div>
<Provider value={store}>
<ToolBar></ToolBar>
</Provider>
</div>
)
}
}
网友评论