react学习一篇就够了
- 作者: 五速梦信息网
- 时间: 2026年04月04日 13:29
命令
js框架 MVC
安装
npm install create-react-app -g
生成项目(项目名npm发包包命名规范 /^[a-z0-9_-]$/)
create-react-app 项目名字
查看全局安装目录
npm root -g
文件
public 存放的是当前项目的HTML页面(单页面应用放index.html即可)
html 导入的地址应该写成绝对路径 %PUBLIC_URL% public的文件夹
不能用相对路径
src 项目结构最主要的目录,后期的js,路由组件都放这里
index.js 是当前目录的入口文件
react-scripts 是webpack的所有配置
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
执行命令 npm run start /yarn start
React脚手架的深入剖析
暴露webpack配置项
为了结构的美化,把所有的webpack配置等都隐藏到了node_modules中(react-script)
yarn eject
首先会提示确认是否执行eject操作,操作是不可逆转的,一旦暴露出来配置项,就无法再隐藏回去了
报错信息
Remove untracked files, stash or commit any changes, and try again.
如果当前的项目基于git管理,在执行eject的时候,如果还没有提交到历史区内容,需要先提交历史区,然后再eject才可以,否则报错
* 需要在vcs 里面commit 进行git操作
再进行 yarn eject
之后多个两个文件夹
config 存放的是webpack的配置文件
webpack.config.dev.js 开发环境下的配置项(yarn start)
webpack.config.prod.js 生产环境下的配置项(yarn build)
scripts 存放的是可执行脚本的js文件
start.js yarn start执行的就是这个js
build.js yarn build 执行的就是这个就是
配置less
yarn add less less-loader
less 开发和生产都需要改
参考
https://www.cnblogs.com/esofar/p/9631657.html
https://www.cnblogs.com/jayxiangnan/p/9116663.html
set HTTPS=true&&npm start 开启HTTPS协议模式
set PORT=63341 修改端口号
配置sass
yarn add node-sass sass-loader -D
如果yarn不能安装就用cnpm
less类似一样的
{
test:/\.scss$/,
loaders:['style-loader','css-loader','sass-loader'],
},
npm install less less-loader --save-dev
去掉webstorm 报灰色线
Editor -> Colors & Fonts -> General , 在Errors and Warnings里把Wadk Warning里的 两项勾选去掉。
撤销工作区的修改
已修改,未暂存(撤销工作区的修改)
git reset --hard
react & react-dom
渐进式框架
我们应该把框架的功能进行拆分,用户想用什么,让其自己自由组合即可
全家桶
渐进式框架N多部分的组合
VUE全局桶(vue-cli/vue/vue-router/vuex/axios(fetch)/vue element(vant))
REACT全家桶: create-react-app/react/react-dom/react-router/redux/react-redux/axios/ant/sage/mobx
react:REACT框架的核心部分,提供了Component类可以共我们进行组件开发,提供了钩子函数(生命周期函数)
所有的生命周期函数都是基于回调函数完成的
react-dom :把JSX语法(REACT特有的语法)渲染为真实DOM(能够展示的结构都叫真实的DOM)
* 不推荐jsx的容器是body
* 只能出现一个根元素
* 给元素设置样式类用的是className而不是class
* style={{}}
* jsx元素设置属性 ,属性值对应大括号中 对象,函数都可以放(也可以放js表达式)
将数据嵌入jsx中,可以嵌入变量或者直接的数据值
let name='xxx';
ReactDOM.render(<div>
<h1>{name}</h1>
<h2>{'haha'}</h2>
</div>)
不能嵌入对象(代指: {} /^$/ 日期对象 函数 数据中的某一项是前面也不行)
可以嵌入基本类型值(null/undefined/布尔值都是空元素,也就是不显示任何内容)
把JSX(虚拟DOM) 变为真实的DOM(不太理解)--(8,9)
循环创建jsx元素需要设置标识key,并且在当前循环的时候,这个key需要唯一
let name='珠峰培训',
data=[{id:1,title:'xxx'},{id:2, title: 'xxx'}];
ReactDOM.render(<ul style={{color:'red'}} className={'box clearfix'} OnClick={(ev)=>{
console.log(ev);
}}>
{data.map((item,index)=>{
return <li key={index}>
{item.id}
{item.title}
</li>
})}
</ul>,root);
使用三元运算符解决判断操作(if和swich是不可以的)
React是如何把jsx元素转换为真实的DOM元素并且添加到页面中
基于babel/babel-loader: 把jsx语法编译为react.create-Element这种模式
create-Element 至少有两个参数,没有上限
第一个: 标签名(字符串)
第二个:属性(没有给元素设置null)
其他:当前元素的所有子元素内容
执行create-Element 把传递的参数最后处理成为一个对象
React 组件
组件/模块管理 ,就是把一个程序划分为一个个组件来单独处理
优势
- 有助于多人协助开发
- 提高复用性
React创建组件有两种方式
- 函数声明式组件
- 基于继承component类来创建组件
src->component 这个文件夹存放开发的组件
create-element 在处理的时候,遇到一个组件,返回的对象中type就不再是字符串,而是一个函数(类),但是属性还是props中
({
type:Dialog,
props:{
lx:1,
con:'xxx',
children:一个值或者一个数组
}
}
首先判断type是什么类型,如果是字符串就创建一个元素标签,如果函数或者类,就把函数执行,把props中的每一项(包含children传递给函数)
React.Children.map
基于继承component类创建组件
基于create-element 把jax 转换为一个对象,当react渲染这个对象的时候,遇到type是一个函数或者类,不是直接创建元素,而是先把方法执行:
* 如果是函数式声明的组件,就把它当作普通方法执行(方法中的this是undefiend),把函数返回的jsx元素进行渲染
* 如果是类声明式的组件,会把房钱类new它执行,创建类的一个实例(当前本次调用组件就是它的实例)执行constructor之后,会执行this.render(),把render中返回的jsx拿过来渲染,所以 类声明式组件,必须有一个render的方法,方法中需要一个jsx元素
但是不管是哪一种方式,最后都会拿解析出来的props属性对象作为实参给对应的函数或者类
创建组件有两种方式"函数式","创建类式"
ReactDOM.render(<div>
/*单闭合*/
<Vote title={xxx}/>
/*双闭合*/
<Vote>
<p>11111111</p>
</Vote>
</div>)
import React from 'react';
exprot default function Vote(props){
return <div className={'penel panel-default'}>
{props.Children}
{props.Children.map(props,children,item=>{return item;})}
</div>
}
import React from 'react';
//ref是react操作DOM的方案
//* 给需要操作的元素设置ref(保持唯一性,否则会冲突覆盖)
//* 在实例上挂载了refs属性,他是一个对象,存储了所有设置ref的元素(ref值:元素对象)
export default class Vote extends React.Component{
constructor(props){
super(props); //React.Component.call(this)可以把component中的私有实例继承过来,this.props/this.state(this.setState)/this.content/this.refs/this.updater
//初始化状态
this.state={
n:0,
m:0,
}
}
//状态处理方式
render(){
let {title,children}=this.props,
{n,m}=this.state;
return <div>
支持:<span>{m}</span>
反对: <span>{n}</span>
</div>
}
//DOM处理方式
render(){
let {title,children}=this.props,
{n,m}=this.state;
return <div>
支持:<span ref={'AA'}>0</span>
反对: <span ref={'BB'}>0</span>
平局值: <span ref={'CC'}>0</span>
</div>
}
suport=ev=>{
this.refs.AA.innerHTML++;
this.computed();
}
suport=ev=>{
this.refs.BB.innerHTML++;
this.computed();
}
computed=()=>{
let {AA,BB}=this.refs;
//然后再进行操作
}
supprot=ev=>{
this.refs.AA.innerHTML++;
//使用箭头函数式为了保证方法中this永远是实例本身(无论在哪执行这个方法)
//ev.target获取当前操作的事件源(dom元素)
this.setState({
//修改状态信息并且通知render重新渲染(异步操作:如果有其他代码执行,先执行其他代码,然后再通知状态修改)
n:this.state.n+1
},()=>{
//回调函数一般不用,当通知状态修改完成,并且页面重新渲染完成后,执行回调
})
}
}
yarn add prop-types
基于这个插件我们可以给组件传递的属性设置规则
设置的规则不会影响页面的,但是会控制台报错
显示当前文件的最新版本信
返回上一个版本
生命周期函数(钩子函数)
基本流程
constructor 创建一个组件
componentWillMout 第一次渲染之前
render 第一次渲染
componentDidMout 第一次渲染之后
修改流程:当组件的状态数据发生改变(setState)或者传递给组件的属性发生改变
shouldComponentUpdate 是否允许组件重新渲染(允许则执行后面函数,不允许直接结束即可)
componentWillUpdate 重新熏染之前
render 第二次以后重新渲染
componentDidUpdate 重新渲染之后
属性改变:
componentWillReceiveProps(nextProps/nextState):父组件把传递给组组建的属性发生改变后出发的钩子函数
接受最新属性之前,基于this.props.xxx 获取的是原有的属性信息,nextProps存储的是最新传递的属性信息
shouldComponentUpdate
是否允许组件更新, 返回true是允许,返回false 是不在继续走
componentWillUpdate:
更新之前: 和should一样,方法中通过this.state.xxx 获取的还是更新前的状态信息,方法有两个参数:nextProps/nextState存储的是最新的属性和状态
render 更新
componentDidUpdate 更新之后
卸载
componentWillUnmount :卸载组件之前(一般不用)
React是face-Book 公司开发的一款MVC版js 框架
MVC Model (数据层) View(视图层) controller(控制层)
核心思想: 通过数据的改变来影响视图的渲染(数据)
属性的属性是只读的:只能调用组件时候传递进来,不能自己在组建内部修改(但是可以设置默认值和规则)
复合组件
- 复合组件:父组件嵌套子组件
export default class Vote extends React.Component {
static defaultProps = {
title: '标题不知道,随便投',
};
constructor(props) {
super(props);
}
render() {
let {title} = this.props;
return <VoteHead title={title}/>
/* 在父组件中
设置子组件上下文属性类型
static childContextTypes={}
获取子组件的上下文(设置子组件的上下文属性信息)
getChildContext(){}
*/
static childContextTypes = {
//设置上下文信息值的类型
n: PropTypes.number,
m: PropTypes.number,
};
getChildContext() {
//return 是啥就是想当于给子组件设置下上文
let {count: {n = 0, m = 0}} = this.props;
return {
n,
m,
}
}
/*
* 子组件设置使用传递进来的上下文类型
* 设置那个的类型,子组件上下文中才有那个属性,不设置是不允许使用的
* this.context.xxx
* 指定的上下文属性类型需要和父组件指定的类型保持一致,否则报错
* */
static contextTypes={
n:PropTypes.number,
m:PropTypes.number
};
constructor(props,context){
super(props,context);
this.context.n=1000
}
/* 在父组件中
设置子组件上下文属性类型
static childContextTypes={}
获取子组件的上下文(设置子组件的上下文属性信息)
getChildContext(){}
*/
static childContextTypes = {
n: PropTypes.number,
m: PropTypes.number,
callBack: PropTypes.func
};
getChildContext() {
//return 是啥就是想当于给子组件设置下上文
//只要render重新渲染,就会执行这个方法,重新更新父组件中的上下文信息,如果父组件上下文
//信息更改了,子组件在重新调取的时候,会使用最新的上下文信息(render=>context=>子组件调取渲染)
let {n, m} = this.state;
return {
n,
m,
callBack: this.updateContext
}
}
updateContext = type => {
//type :'support'/'against'
if (type === 'support') {
this.setState({n: this.state.n + 1});
return;
}
return this.setState({m:this.state.m-1})
};
//子组件
<button className={'btn btn-danger'} onClick={
()=>{
callBack('against');
}
}>反对</button>
- 平行组件:兄弟组件或者毫无关系的两个组件
yarn add redux react-redux
//index.js
//创建一个容器: 需要把reducer 传递进来(登记了所有状态更改的信息)
import {createStore} from 'redux';
/*reducer 作用:
1. 记录了所有状态修改的信息(根据行为标识走不同的修改任务)
2. 修改容器中的状态信息
[参数]
state:容器中原有的状态信息(如果第一次使用,没有原有状态,给一个厨师默认值
action: dispatch 任务派发的时候传递的行为对象(这个对象中必有一个type属性,是操作的行为标识,
reducer 就是根据这个行为标识来识别修改状态信息
* */
let reducer = (state = {n: 0, m: 0}, action) => {
switch (action.type) {
case 'VOTE_SUPPORT':
//vote_support
state = {...state, n: state.n + 1};
break;
case 'VOTE_AGAINST':
//vote_against
state = {...state, m: state.m + 1};
break;
}
return state;// 只有把最新的state返回,原有的状态才会修改
};
let store = createStore(reducer);
/*
* 创建store 提供三个方法:
* dispatch: 派发行为(传递一个对象,对象中有一个type属性,通知reducer修改状态信息
* subscribe: 事件池追加方法
* getState: 获取最新管理的状态信息
* */
<Vote title={'英格兰对战巴拿马,合力必胜'}
count={{
n: 100,
m: 78
}}
store={store}/>
//Vote.js
import React from 'react';
import PropTypes from 'prop-types';
import VoteHead from './VoteHead';
import VoteBody from './VoteBody';
import VoteFooter from "./VoteFooter";
export default class Vote extends React.Component {
static defaultProps = {
title: '',
count: {
n: 0,
m: 0,
}
};
constructor(props) {
super(props);
};
render() {
let {store} = this.props;
return <section className={'panel-heading'} style={{width: '50%', height: '20px auto'}}>
<VoteHead title={this.props.title}/>
<VoteBody store={store}/>
<VoteFooter store={store}/>
</section>
}
}
//VoteBody.js
import React from 'react';
import PropTypes from 'prop-types';
export default class VoteBody extends React.Component {
constructor(props) {
super(props);
//init state
let {store: {getState}} = this.props,
{n, m} = getState();
this.state = {n, m};
}
componentDidMount() {
let {store: {getState, subscribe}} = this.props;
let unsubscribe = subscribe(() => {
let {n, m} = getState();
this.setState({
n,
m
})
});
//unsubscribe(): 当前追加的方法移出,接触绑定的方式
}
render() {
let {n, m} = this.state,
rate = (n / (n + m)) * 100;
if (isNaN(rate)) {
rate = 0;
}
return <div className={'panel-body'}>
支持人数: <span>{n}</span>
<br/>
反对人数: <span>{m}</span>
<br/>
支持比率: <span>{rate.toFixed(2) + '%'}</span>
</div>;
}
}
//VoteFooter.js
import React from 'react';
import PropTypes from 'prop-types';
export default class VoteFooter extends React.Component {
constructor(props, context) {
super(props, context);
}
render() {
let {store: {dispatch}} = this.props;
return <div className={'panel-footer'}>
<button className={'btn btn-success'}
onClick={() => {
dispatch({
type: 'VOTE_SUPPORT'
})
}}
>支持
</button>
<button className={'btn btn-danger'} onClick={
() => {
dispatch({
type: 'VOTE_AGAINST'
})
}
}>反对
</button>
</div>
}
}
Redux
redux:进行状态统一管理的类库(适用于任何技术体系的项目)
- 只要两个或者多个组件之间想要实现信息的共享,都可以基于redux解决,把共享的信息到redux容器中进行管理
- 还可以使用redux做临时存储:页面加载的时候,把从服务器获取的数据信息存储到redux中,组件渲染需要的数据,redux中,这样只要页面不刷新,路由切换的时候,再次渲染组件不需要重新从服务器拉取数据,直接从redux中获取即可:页面刷新,从头开始(这套方案代替了localStorage本地存储来实现数据缓存)
Redex管理文件夹
store REDUX管理文件夹
* action 派发行为集合
* vote.js
* ...
* index.js 所有分模块行为的汇总
*
* reducer 管理员集合
* vote.js
* ...
* index.js 所有管理员的集合汇总
*
* action-types.js 所有行为标识
* index.js 创建REDUX容器
Redex工程化案例
/*
* store
* reducer: 存放每一个模块 reducer
* vote.js
* personal.js
* ...
* index.js 把每一个模块reducer最后合并成reducer
* action 存放每一个模块需要进行的派发任务(ActionCreator)
*
* */
import {createStore} from 'redux';
import reducer from './reducer';
let store = createStore(reducer);
export default store;
/*
* 管控当前项目中所有redux任务派发中需要的行为标识action-type
* */
//vote_support
export const vote_support = 'vote_support';
export const vote_against = 'vote_against';
//personal
export const personal_init = 'personal_init';
index.js
======
/*
* 合并所有的action-creator,类似于reducer合并,为了防止冲突,合并后的对象是以版块名称单独划分管理
* */
import vote from './vote';
import personal from './personal';
let action ={
vote,
personal
};
export default action;
personal.js
======
import * as TYPE from '../action-types';
let personal = {};
export default personal;
vote.js
======
/*
* 每个版块单独的action-creator :就是把dispatch派发时候需要传递的action对象进一步统一封装处理
* react-redux中会体验到他的好处
* */
import * as TYPE from '../action-types';
let vote={
support(){
//dispatch 派发的时候需要传递啥就返回啥即可
return {
type: TYPE.vote_support
};
},
against(){
return {
type: TYPE.vote_against
}
}
};
export default vote;
index.js
=====
/*
* 把每一个模块但是设置的reducer函数最后合并成为总的reducer
* 为了保证合并reducer过程中,每个模块管理的状态信息不会相互冲突
* redux在合并的时候容器中的状态进行分开管理(一合并reducer时候设置的属性名作为状态
* 划分的属性名,把各个版块管理的状态放到自己的属性下
* state={
* vote:{
n:0,
m:0
* },
* personal:{
* baseInfo:{}
* }
* }
* store.get-state().vote.n以后获取状态信息的时候,也需要把vote加上
* */
import {combineReducers} from 'redux';
import vote from './vote';
import personal from './personal';
let reducer=combineReducers({
vote,
personal
});
export default reducer;
personal.js
======
import * as TYPE from '../action-types';
export default function vote(state = {
baseInfo:{}
}, action) {
//...
return state;
}
vote.js
=====
//vote版块的reducer
// state: 原始redux管理的状态管理(设置初始值)
// action: dispatch派发的时候传递的行为对象(type,)
import * as TYPE from '../action-types';
//把模块中所有导出的内容全部导出,并重新命名为type
export default function vote(state = {
n: 0,
m: 0,
}, action) {
switch (action.type) {
case TYPE.vote_support:
state = {...state, n: state.n + 1};
break;
case TYPE.vote_against:
state = {...state, m: state.m + 1};
break;
}
return state;
}
import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.css'
import Vote from './component/Vote/Vote';
import store from './store';
ReactDOM.render(<main>
<Vote title={'英格兰对战巴拿马,合力必胜'}
count={{
n: 100,
m: 78
}}
store={store}/>
</main>, document.querySelector('#root'));
Vote.js
=====
render() {
let {store} = this.props;
return <section className={'panel-heading'} style={{width: '50%', height: '20px auto'}}>
<VoteHead title={this.props.title}/>
<VoteBody store={store}/>
<VoteFooter store={store}/>
</section>
}
VoteBody.js
=====
import React from 'react';
import PropTypes from 'prop-types';
export default class VoteBody extends React.Component {
constructor(props) {
super(props);
//init state
let {n, m} = this.props.store.getState().vote;
this.state = {n, m};
}
componentDidMount() {
this.props.store.subscribe(() => {
let {n, m} = this.props.store.getState().vote;
this.setState({
n,
m
})
});
//unsubscribe(): 当前追加的方法移出,接触绑定的方式
}
render() {
let {n, m} = this.state,
rate = (n / (n + m)) * 100;
if (isNaN(rate)) {
rate = 0;
}
return <div className={'panel-body'}>
支持人数: <span>{n}</span>
<br/>
反对人数: <span>{m}</span>
<br/>
支持比率: <span>{rate.toFixed(2) + '%'}</span>
</div>;
}
}
VoteFooter.js
=====
import React from 'react';
import PropTypes from 'prop-types';
import action from '../../store/action';
export default class VoteFooter extends React.Component {
constructor(props, context) {
super(props, context);
}
render() {
let {store: {dispatch}} = this.props;
return <div className={'panel-footer'}>
<button className={'btn btn-success'}
onClick={() => {
this.props.store.dispatch(action.vote.support())
}}
>支持
</button>
<button className={'btn btn-danger'} onClick={
() => {
this.props.store.dispatch(action.vote.against())
}
}>反对
</button>
</div>
}
}
react-redux
```js
export default connect([mapStateToProps],[mapDispatchToProps])(自己创建的组件)
```
////把redux容器中的状态信息遍历,赋值给当前组件的属性(state)
let mapStateToProps=state=>{
//state就是redux容器中状态信息
//我们返回的是啥,就把它挂载到当前组件的属性上(redux存储很多信息,我们想用啥就返回啥即可)
return {
...state.vote
}
};
//把redux的dispatch 派发行为遍历,也复制给组件的属性(ActionCreator)
let mapDispatchToProps=dispatch=>{
//dispatch:store中存储的dispatch方法
//返回的是啥,就想当于把啥挂载到组件的属性上(一般我们挂载一些方法,这
// 些方法完成dispatch派发信息
return {
init(initData) {
dispatch(action.vote.init(initData));
}
}
};
export default connect([mapStateToProps],[mapDispatchToProps])(VoteBase)
=======================
export default connect({state=>({...state.vote})},action.vote)(VoteBase)
react-redux把action-creator中编写方法(返回action对象的方法),自动构造dispatch派发任务的方法,也就是mapDispatchToProps这种格式把redux容器中的状态信息遍历,赋值给当前组件的属性(state)
[todo](file:\H:\珠峰\2018年第二期源码、笔记\2018年第二期源码、笔记\WEEK12\day2)实例
单页面应用(SPA)多页面应用(MPA)
多页面应用(MPA)
一个项目由很多页面组成,使用这个产品,主要就是页面之间的跳转(pc端多页面应用居多);
基于框架开发的时候,需要在webapck中配置多入口,每一个入口对应一个页面;
单页面应用(SPA)
只有一个页面,所有需要展示的内容都在这一个页面中实现切换,webapck只需要配置一个入口即可
移动端单页面应用居多或者pc端系统类也是单页面应用为主
如何实现单页面应用
弊端: 由于首页中的内容包含了所有模块的信息,所以第一次加载速度很慢
解决vue/react 实现模块化组件化开发,基于他们提供的路由实现SPA单页面应用,基于webpack打包
路由
yarn add react-router-dom
BrowerRouter
<BrowserRouter basename="/calendar">
<Link to="/today" />
</BrowserRouter>
//最后呈现的地址 /calendar/today
// 使用默认的确认函数
const getConfirmation = (message, callback) => {
const allowTransition = window.confirm(message)
callback(allowTransition)
}
<BrowserRouter getUserConfirmation={getConfirmation}/>
HashRouter
Switch组件可以解决这个问题,和switch case 一样,只要有一种校验成功,就不再向后校验
<HashRouter>
<Switch>
<Route path={'/'} exact component={A}>AAA</Route>
<Route path={'/user'} component={B}/>
<Route path={'/pay'} render={() => {
let flag = localStorage.getItem('flag');
if (flag && flag === 'safe') {
return <C/>
}
return '权限不安全';
}}/>
//上述都设置完成后,会在末尾设置一个匹配:以上都不符合的情况下,我们路由地址是违法的
//(不设置path就是匹配所有的地址规则)
<Route render={ ()=>{
return <div>404</div>
}}/>
//重定向
//to [string]
//
<Redirect to='/'/>
</Switch>
</HashRouter>
Link
<Link to={{
pathname: '/courses',
search: '?sort=name',
hash: '#the-hash',
state: {
fromDashboard: true
}
}} />
NavLink
跟link类似,都是为了实现路由切换跳转的,不同在于,nav-link组件在当前页面hash和组件对应地址相吻合的时候,会默认给组件加一个active样式,让其选中态
Nav-Link不是点击谁,谁有选中的样式(但是可以路由切换),当前页面哈希后的地址和Nav-Link中的to进行比较,哪个匹配了,哪个才有选中的样式
to和replace等属性都有,用法一样
activeClassName:把默认的active样式改为自己设定的
activeSyle:把匹配的这个nav-link设置行内样式
exact & strict控制匹配的时候是否是严格匹配
isActive: 匹配后执行对应的函数
with-Router
export default withRouter(connect()(组件));
先把nav基于connect高阶一下,返回的是一个代理组件proxy,
把返回的代理组件受路由管控
Redirect
<Redirect to={{
pathname: '/login',
search: '?utm=your+face',
state: {
referrer: currentLocation
}
}} />
<Redirect from={'/custom'} to={'/custom/list'}/>
当请求的是/custom的时候,直接跳转到/custom/list的路由地址
qs
yarn add qs
问号传参
OA和ERP
OA:企业办公管理系统(偏向于有助于日常办公)
ERP: 企业战略资源管理系统(偏向于有管理思想)
- 钉钉
- TAPD
- 今目标
- 纷享销客
CRM:客户管理系统
CMS:内容管理系统(内容分发平台)
IM:即时通信系统
redux中间件
redux-logger:能够在控制台清晰的展示当前redux操作的流程和信息(原有状态,派发信息,修改后的状态)
redux-thunk: 处理异步的dispatch派发
redux-promise: 在dispatch派发的时候支持promise操作
yarn add redux-logger redux-thunk redux-promise
store/index.js
=====
import {createStore, applyMiddleware} from 'redux';//applyMiddleware导入中间件
import reduxLogger from 'redux-logger';
import reduxThunk from 'redux-thunk';
import reduxPromise from 'redux-promise';
import reducer from './reducer';
let store = createStore(reducer, applyMiddleware(reduxLogger, reduxThunk, reduxPromise));
export default store;
//=>PROMISE中间件的语法
create(payload) {
return {
type: TYPES.CUSTOM_CREATE,
//=>传递给REDUCER的PAYLOAD需要等待PROMISE成功,把成功的结果传递过去
payload: new Promise(resolve => {
setTimeout(() => {
resolve(payload);
}, 3000);
})
}
}
create(payload) {
//=>THUNK中间件的使用语法:在指定执行派发任务的时候,等待3000MS后在派发
return dispatch => {
//=>DISPATCH都传递给我们了,我们想什么时候派发,自己搞定即可
setTimeout(() => {
dispatch({
type: TYPES.CUSTOM_CREATE,
payload
});
}, 3000);
};
}
[路由问号传参案例](file:\H:\珠峰\2018年第二期源码、笔记\2018年第二期源码、笔记\WEEK12\day3\src)
Ant Desion UI框架
yarn add antd;
复习
{React.createElement('a',{href:'http://www.baidu.com'},'Hello')}
//标签 属性 子元素
class HelloMessage extends Component{
render(){
let child=React.createElement('li',{className:'ddd'},'我是子页面');
return <div>Hello {this.props.name}
{React.createElement('a',{href:'http://www.baidu.com'},'Hello')}
<br/>
{React.createElement('ul',{className:'ccc'},child
)}
</div>
}
}
style 属性应该由CSS属性构成的JS对象
* className=''
* style={{fontSize:50,backgroundColor:'red'}} // zIndex 多峰命名
let styles={
fontSize:50,
fontWeight: 'bold',
backgroundColor: 'red',
};
{{styles}}
模拟 if
{this.state.tags.length === 0 && '等于0'} //A为真返回B
renderTags(){
if(this.state.tags.length===0) return <p>里面没有元素</p>
return <ul>
{this.state.tags.map((tag,index)=><li key={index}>{tag}</li>)}
<hr />
</ul>
}
{this.renderTags()}
props 属性
state 组件的状态 可以通过 this.setState进行更改
无状态组件
const Hellos = (props) => <div>Hello {props.name}</div>;
<Hellos name={'zhangsan'}/>
有状态组件
//定义一个时间的方法,挂载前开始定时器执行这个方法,卸载后清除挂载前的那个定时器方法
export default class LikeButton extends React.Component {
constructor(props) {
super(props);
//初始化状态
this.state = {
data: new Date()
}
};
componentDidMount(){
this.timerId=setInterval(
()=>this.tick()
)
}
//方法
tick(){
this.setState({
data:new Date()
})
}
componentWillUnmount(){
clearInterval(this.timerId);
}
render() {
return <div>
<h3>{this.state.data.toLocaleTimeString()}</h3>
</div>
}
}
props 对于使用他的组件来说是只读的,只能通过父组件进行修改
state 可以通过 this.setState({ }) 进行修改
注意不要在push pop shift unshift splice 等方法修改
应该用concat slice filter 会放回一个新数组
原生事件
可以再componentDidMount方法中通过addEventListener 绑定浏览器原生事件
componentWillUnmount 方法解除 removeEventListener
在dom 中 设置 ref属性指定一个名称 通过 this.refs.指定名称获取
组合组件
父组件 <Avatar username="pwh" />
const Avatar = (props) => {
return (
<div>
//子组件 通过属性传递
<ProfilePic username={props.username} />
<ProfileLink username={props.username} />
</div>
);
}
循环的时候必须要给key
// arr是在父组件里面声明的arr数组的属性
<ul>{this.props.arr.map((v,i)=>{
return <li key={i}>{v}</li>
})}</ul>
组件标签里面包含的子元素通过 this.props.children
<LikeButton username={'pwh'} arr={[1,2,3,4]}>
<span>12123</span>
<p>我是一个p标签</p>
</LikeButton>
props.children通常是一个组件对象的数组,当 props.children是唯一的子元素,那就不是数组
点击事件的内联样式
onClick={ ()=>(console.log(1))}
第二种方法
onClick={this.handleClick} //记得不要再这里带(e)参数 会报错的
<div onClick={this.handleClick.bind(this)}>${this.props.name}</div>
handleClick=(e)=>{
console.log(e.target.innerHTML);
}; //函数建议使用箭头函数的写法
通过 setState来修改state
this.setState({
count: this.state.count+1
})
store有四个方法。
getState: 获取应用当前 state。
subscribe:添加监听器。
dispatch:分发 action。更新 state。
replaceReducer:替换 store 当前用来处理 state 的 reducer。
两者的关系是: state=store.getState()
常用的是dispatch,这是修改State的唯一途径,使用起来也非常简单。
import {createState} from 'redux';
function counter(state=0,action) {
switch(action.type){
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state-1
default:
return state
}
}
let store=createState(counter);
store.subscribe(()=>{
console.log(store.getState());
});
store.dispatch({type:"INCREMENT"});
action 唯一的约束仅仅就是包含一个type
store由redux的createStore(reducer)生成的
state通过store.getState()获取的
action本质上是一个包含type属性的普通对象
改变 state必须dispatch一个action
reducer 本质上action.type 来更新的
实际上state就是所有reducer返回的汇总
redux有五个API
createStore(reducer,[])
combineReducers(reducers)
applyMiddleware(...middlewares)
bindActionCreators(actionCreatore,dispatch)
compose(...functions)
Redux 强调三大基本原则
* 唯一数据源
* 保持状态只读
* 数据改变只能通过纯函数完成
const todo={
TOGGLE_TODO:'TOGGLE_TODO',
GET_TODOS:'GET_TODOS',
toggleTodo({ items,id }) {
return {
type: todo.TOGGLE_TODO,
items:items,
id:id
}
},
getTodos({items}){
return {
type:todo.GET_TODOS,
items:items
}
}
};
export default todo;
// ======
export default function(state = {默认值}, action) {
switch(action.type){
case GET_TODOS:
return {todos:[...action.items]}
case TOGGLE_TODO://deleted=true
return {
todos:action.items.map((i)=>{
if(i.id===action.id){
return {
...i,
status:i.status===0?1:0
}
}else{
return {
...i
}
}
})
}
default:
return state;
}
}
const store = createStore(todo);
redux-hook
dva.js
- 上一篇: react中怎么复制一个对象
- 下一篇: react项目中使用立体图表
相关文章
-
react中怎么复制一个对象
react中怎么复制一个对象
- 互联网
- 2026年04月04日
-
RedHat6Centos6.5安装mongodb php driver
RedHat6Centos6.5安装mongodb php driver
- 互联网
- 2026年04月04日
-
Redis Java客户端的选择
Redis Java客户端的选择
- 互联网
- 2026年04月04日
-
react项目中使用立体图表
react项目中使用立体图表
- 互联网
- 2026年04月04日
-
react拖拽插入排序
react拖拽插入排序
- 互联网
- 2026年04月04日
-
react实现登录注册
react实现登录注册
- 互联网
- 2026年04月04日






