手把手教你写react项目
1.创建项目
cnpm / npm i create-react-app -g
npx create-react-app myapp

2.抽离配置文件
cd myapp
运行 npm run eject 抽离配置文件

修改package.json ,配置dev指令

3.配置项目
配置src文件夹的别名 @
pakeage.json的alias选项中:
'react-native': 'react-native-web',
'@': path.join(__dirname,'../','src')
配置sass
npm i node-sass -D
4.项目基本结构
1.在App.js,创建样式基本结构
import React from 'react';
function App() {
return (
<div className="container">
<header className="header">header</header>
<div className="content">cont</div>
<footer className="footer">foot</footer>
</div>
);
}
export default App;
2.创建基本页面
在src新建各个页面

3.入口文件处引入相关文件并且配置
路由:
npm i react-router-dom -S
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
//给根节点root要通过路由去渲染页面,只有一个子元素switch
ReactDOM.render(
<Router>
<Switch>
<Route path="/" component={App}/>
</Switch>
</Router>
, document.getElementById('root'));
4.app.js
import {Route,Switch} from 'react-router-dom';
return (
<div className="container">
<Switch>
<route path="/home" component={Home} />
<route path="/car" component={Car} />
<route path="/kind" component={Kind} />
<route path="/mine" component={Mine} />
</Switch>
<footer className="footer">foot</footer>
</div>
);
但是什么都不输入的时候,不出效果 ------- 重定向
import {Route,Switch,Redirect} from 'react-router-dom';
<Redirect to="/home"/>
5.底部布局,完成跳转
路由的跳转、声明式跳转
Link ---- 选中无效果
NavLink ---- 选中有效果
import {Route,Switch,Redirect, NavLink} from 'react-router-dom';
<footer className="footer">
<ul>
<NavLink to="/home">首页</NavLink> //会被转成a标签,设置样式选中a标签
<NavLink to="/kind">分类</NavLink> //选中的会有一个class=active类
<NavLink to="/car">购物车</NavLink>
<NavLink to="/mine">我的</NavLink>
</ul>
</footer>
5.请求数据
父组件给子组件传值:在父组件调用子组建的地方添加一个自定义的属性,属性的值就是你要传的值,如果值是一个变量就用到大括号,在定义子组件的地方,如果子组件是一个函数式组件,默认的参数点属性名就是传递的值,如果是类组件,this.props.属性名就是传过来的值。
src新建components文件,中Prolist组件
import React from 'react'
export default (props)=>{
return (
<ul>
{
props.prolist.map((item,index)=>(
<li key={index}>{item.title}</li>
))
}
</ul>
)
}
在父组件请求数据:
componentDidMount(){
axios.get('https://www.daxunxun.com/douban').then(res=>{
this.setState({
prolist:res.data
})
})
}
render(){
return (
<div className="box">
<header className="header">header</header>
<div className="content">
<Prolist prolist={this.state.prolist}/>
</div>
</div>
)
}
6.构建详情页面
入口找布局,布局找页面,页面找组件
默认布局和页面可以通过this.props访问路由,默认组件不能直接访问,如果想要组件访问路由,在调用该组件的地方传一个{…this.props}
在index.js中找app布局或者detail布局,在app.js中找页面
新建一个布局other.js,此时有两个布局文件,还有一个是APP.JS
<Switch>
<Route path="/detail" component={ Detail }/>
</Switch>
创建路由:在index.js,
import Detail from '@/otherApp'
<Switch>
<Route path = "/other" component={ OtherApp }/>
<Route path = "/" component={ App }/>
</Switch>
但是当你放入login时,就会重定向了
在detailApp中,前边加上detail/login 就可以了
<Switch>
<Route path="/other/login" component={ Login }/>
<Route path="/other/detail" component={ Detail }/>
</Switch>
7.跳转详情页面
1.声明式跳转
在prolist组件中:
传值:在otherApp中: 加上/:id
<Route path="/other/detail/:id" component={ Detail }/>
在prolist组件:
import React from 'react'
import {Link} from 'react-router-dom'
export default (props)=>{
return (
<ul>
{
props.prolist.map((item,index)=>(
<Link to={ "/other/detail/" + item.id } key={index}>{item.title}</Link> //遇到变量就腰用到{}
))
}
</ul>
)
}
详情页去获取数据
import React , {Component} from 'react'
import axios from 'axios'
export default class extends Component {
constructor(props){
super(props)
this.state={
title:''
}
}
componentDidMount(){
const {props:{match:{params:{id}}}} =this
axios.get('https://www.daxunxun.com/detail?id='+id).then(res=>{
this.setState({
title:res.data[0].title
})
})
}
render(){
return (
<div className="box">
<header className="header">header</header>
<div className="content">
{this.state.title}
</div>
</div>
)
}
}
2.编程式跳转
默认布局和页面可以通过this.props访问路由,默认组件不能直接访问,如果想要组件访问路由,在调用该组件的地方传一个{…this.props}
<Prolist prolist={this.state.prolist}{...this.props}/>
在组件中
import React from 'react'
export default (props)=>{
return (
<ul>
{
props.prolist.map((item,index)=>(
<li key={index} onClick={()=>{
props.history.push('/other/detail/' + item.id)
//repalce goback
}}>
{item.title}
</li>
))
}
</ul>
)
}
8.重定向遇到404
<Redirect from="/" exact to="/home"/> //只有当重定向是/才会重定向到home
编写一个404页面
9.UI库使用 antd-mobile
https://mobile.ant.design/docs/react/introduce-cn
安装依赖
npm install antd-mobile --save
FastClick
Pc端使用的是click事件,移动端如果也使用click事件,会发生“点击穿透”的现象(手机网页 双击屏幕 会放大页面,点击事件延迟300ms — 移动端补充章节)
复制index.html
自动引入:
10.状态管理器
11.反向代理
12.mock模拟数据
13.diff算法
render 执行的结果得到的不是真正的 DOM 节点.结果仅仅是轻量级的 JavaScript 对象, 我们称之为 virtual DOM—虚拟DOM
diff算法:操作dom时只会去改变变化的地方,根据标签的层级从外向内查找变化的地方标签存在则复用标签,不存在就创建虚拟dom:react中的render方法就是虚拟的dom
在遍历时加一个key
14.受控组件和非受控组件
15.token
16.hook
特殊的函数,使用hook可在函数式组件中使用状态,使用useState唯一的参数初始值,在定义的方法中修改状态
可在函数式组件中使用状态
- 声明一个新的叫做 “count” 的 state 变量,此处使用 [], 不能使用 {}
const Com = () => {
// 声明一个新的叫做 “count” 的 state 变量,此处使用 [], 不能使用 {}
const [ count, setCount ] = useState(1)
return (
<div>
<button onClick = { () => {
let a = count + 1
setCount(a)
}}>+1</button>
{ count }
</div>
)
}
export default Com
2.useEffect
副作用,若有数据请求会一直执行
import React, { useState, useEffect } from 'react'
import axios from 'axios'
// 使用 HOOK useState 可以在 函数式组件 中 用状态
const Com = () => {
// 声明一个新的叫做 “count” 的 state 变量,此处使用 [], 不能使用 {}
const [ count, setCount ] = useState(1)
const [ bannlist, setBannerlist ]= useState([])
useEffect(() => {
axios.get('https://www.daxunxun.com/banner').then(res => {
setBannerlist(res.data)
})
})
return (
<div>
<button onClick = { () => {
let a = count + 1
setCount(a)
}}>+1</button>
{ count }
<ul>
{
bannlist.map((item, index) => (
<li key = { index }> { item }</li>
))
}
</ul>
</div>
)
}
export default Com
性能优化
只请求一次,清除上一次,创建下一次。后加[ ] ,不会再触发,
usecontext
useReducer是useState的替代,只能针对本组件。
ref
获取所有节点,函数组件不可用ref
console.log(this.refs)
类组件this.refs.refs获取dom节点
react的插槽
export default (props) => {
return (
<header>
{ props.children }
</header>
)
}
//在调用的地方
<Header>
<div className="left">左</div>
<div className="center">中</div>
<div className="right">右</div>
</Header>
高阶组件
高阶组件HOC,复用组件的逻辑,组件作为一个参数返回一个新的 参数
解决HOC解决横切关注点问题,until接受参数(com,data),在组件中until。connect(传一个组件和数据)
虚拟化长列表,利用滚动技术,react-window模块,返回顶部
mobx状态管理
全家桶
vue
vue + vue-router + axios/fetch + vuex + mint-ui/vant/element-ui/iview
ES7语法:装饰器
是一个函数,可装饰类或类中的成员
举例:object.fefineproperty( )
indexstore
import HomeStore from "./home";
import KindStore from "./kind";
class Store {
constructor () {
this.home = new HomeStore(this);
this.kind = new KindStore(this);
}
}
export default new Store()
import { observable, action } from 'mobx'
class HomeStore {
@observable bannerlist = []
@observable prolist = []
constructor (store) {
this.store = store
this.changeBannerlist = this.changeBannerlist.bind(this)
this.changeProlist = this.changeProlist.bind(this)
}
@action
changeBannerlist (data) {
this.bannerlist = data
}
@action
changeProlist (data) {
this.prolist = data
}
}
export default HomeStore
import axios from 'axios'
@inject('store')
@observer
class Com extends Component {
constructor (props) {
super(props)
this.state = {}
}
componentDidMount () {
axios.get('https://www.daxunxun.com/banner').then(res => {
this.props.store.home.changeBannerlist(res.data)
})
}
