React
react 是什么
用户描述用户界面的js库 (view)
angular mvc
vue mvvm
react属于facebook
版本
15.6 2018上半年 15.6
16 2018下半年 16
引入的文件
1、react.min.js 提供的是React对象
2、actre-dom.min.js 提供了ReactDOM 对象
3、browser.min.js 帮助浏览器解析jsx语法糖
4、rn react-native
a. 网页 B(browser)/S(server) webapp dom bom
react基本语法 + react-dom 可以写网页
b. app C(client)/S(Server) 手机硬件以及ui
react基本语法 +react-native 可以写app
例子:
<body>
<div id="app"></div>
<script type="text/babel">
/*
1. 创建组件 15.6 React.createClass
2. 组件是虚拟dom
3. 将虚拟dom通过 ReactDOM.render(组件标签,要挂载的元素)
4. 组件名必须大写
*/
let Component = React.createClass({
render() {
// render 函数内部 返回jsx
return (
<h1> 你好世界</h1>
)
}
})
// 将组件的虚拟dom挂载到真实dom上
ReactDOM.render(<Component/>,document.getElementById('app'))
</script>
</body>
jsx 语法糖 javascript xhtml
用jsx 来描述组件的虚拟dom
1、jsx写法
<div id='test' class='hehe'>
<p id='p'>
<div></div>
</p>
<span>呵呵</span>
</div>
2、react原生写法
React.createElemet('div',{id:"test",className:"hehe"},[
React.crateElment('p',{id:p},[
React.crateElment('div',{id:p,text:"呵呵"},[])
])
React.crateElment('span',{id:p,text:"呵呵"},[])
])
xhtml 严格模式的HTML
1. 必须只有一个根元素
2. 标签必须闭合
react jsx的注释方式
{/* 注释内容*/}
### 创建组件
引入文件 提供 react reactdom对象 帮助浏览器解析jsx
组件名一定要大写
```
let Component = React.createClass({
render(){
return ( jsx )
}
})
ReactDOM.render(组件名,要挂载的元素)
```
数据和指令
### 数据承载(state和props)
1、state 组件内部的数据 组件内部可以改
getInitialState() 生命周期初始化
getInitialState(){
console.log('初始state的生命周期')
return {
name:'韩梅梅'
}
},
2、props 来自于组件外部的数据 组件内部不能修改
getDefaultProps() 生命周期初始化
1. 组件的内容通过 getDefaultProps生命周期进行初始化
getDefaultProps(){
console.log('初始化props的生命周期')
return {
age:16
}
},
2. 在组件标签上通过自定义属性传递
<Hehe age='999'/>
3. 初始化和传递的冲突以传递的优先级高
4. props传递的数据在组件内部只能使用不能修改
注意(props数据优先)
外部传递和组件内部初始化同时存在以外部传递优先
### 数据绑定
{} 存放变量或者表达式
1. 数字 字符串 可以直接绑定
2. 对象 不能直接绑定
3. 数组 数组的每一项都会被拆分出来
4. 布尔值 null undefined 在页面不会直接显示 配置3元表达式或者其他的表达式
### 指令
react中不存在这种东西 我们自己去实现相同的效果
1. 列表渲染
数组在绑定的时候会被拆解开来 通常结合map实现对数据的处理
写法一(map写在render生命周期里)
let Component = React.createClass({
getInitialState(){
return{
list:['咒怨','午夜凶铃','红色高跟鞋','死亡来电','阴阳瞳']
}
},
render() {
return (
<ul>
{this.state.list.map((item,index)=>{
return(
<li>{item}</li>
)
})}
</ul>
)
}
})
写法二(map独立写成一个方法)
let Component = React.createClass({
getInitialState(){
return{
list:['咒怨','午夜凶铃','红色高跟鞋','死亡来电','阴阳瞳']
}
},
renderList(){
return this.state.list.map((item,index)=>{
return(
<li>{item}</li>
)
})
},
render() {
return (
<ul>
{this.renderList()}
</ul>
)
}
})
2. 条件渲染
a. 三元表达式控制渲染
{show?<div id='test'></div>:''}
b. || 或运算符控制渲染
{!show||<div id='test'></div>}
c. 函数的返回控制渲染
getInitialState(){
return{
show:false
}
},
renderDiv(){
if(this.state.show){
return (<div id = 'test'></div>)
}else{
return null
}
},
render() {
return (
<div>
{this.renderDiv()}
</div>
)
}
3. 属性绑定
希望属性的值是变量
<img src={变量或者表达式}>
注意类名要用className
<div className={this.state.color?'red':'blue'}>
4. 事件绑定
react事件和原生事件类似只需要把事件名写成小驼峰就ok
原生 <div onclick=''></div>
react <div onClick=''></div>
写法一(默认参数e:事件对象)
onClick={(e)=>{
事件处理代码
}}
写法二:不带参数 默认参数是事件对象 千万别加()
onClick={this.fun}
写法三:带参数 通过bind实现 默认参数会放到最后方
onClick={this.fun.bind(null,4,6)}
### 数据变页面变不变(this.setState)
react 中不像vue有数据响应式 要通过setState触发页面的修改
this.setState({要修改的数据:修改的内容},callback())
this.setState({name:'李雷雷'},()=>{
console.log('数据修改完毕',this.state.name)
})
setState 是一个异步方法参数一时要修改的数据
参数2是修改成功之后的回调
组件通信
### 组件嵌套
react组件的嵌套关系随意 虽在外部谁是爸爸
let Son = React.createClass({
render(){
return (
<div className='test2'>
这里是组件二
<Component></Component>
</div>
)
}
})
### 插槽(this.props.children)
和vue中组件标签汇总存放的内容默认不会被渲染 react中没有slot
组件对象下 props.children可以用来获取组件标签中的内容
let Component = React.createClass({
render(){
return(
<div className='test1'>
这是组件1
<Son>
政治老师:底层基础,·决定高层建筑
</Son>
</div>
)
}
})
let Son = React.createClass({
render(){
console.log(this)
return (
<div className='test2'>
这里是组件二
<h1>{this.props.children}</h1>
</div>
)
}
})
### ref
可以绑定dom 也可以绑定组件
通过组件对象下的 refs进行获取
1、绑定dom
let Son = React.createClass({
render(){
return (
<div className='test2'>
这里是组件二
<h1 ref='hehe'>体育老师:受伤了就别逞强了</h1>
<button onClick={()=>{
console.log(this.refs.hehe)
}}>点击</button>
</div>
)
}
})
2、绑定组件
let Component = React.createClass({
render(){
return(
<div className='test1'>
这是组件1
<button onClick={()=>{
console.log(this)
this.refs.son.sayHello()
}}>点击</button>
<hr/>
<Son ref='son'></Son>
</div>
)
}
})
绑定son组件执行son的方法
### react组件通信
一、父子通信 props refs
1、props
{/*父组件通过props自定义属性 将自己的数据传奇给子组件*/}
<Son hair={this.state.hair}></Son>
子组件通过this.props接收
let Son = React.createClass({
render(){
return(
<div className='son'>
<h3>子组件</h3>
头发:{this.props.hair}
</div>
)
}
})
2、refs
父组件通过refs调用子组件的方法
<Son ref='son'></Son>
this.refs.son.change()
二、子父通信 props
{/*通过props 传递方法*/}
<Son fafun={this.changeName}></Son>
// 调用父组件的方法
this.props.fafun('李雷雷')
三、亲兄弟通信 状态提升
四、远亲通信 全局状态管理 redux
react 脚手架工具
npm install create-react-app -g
create-react-app -V
create-react-app 项目名字 通过脚手架工具创建项目
注意:
部分插件的版本依赖问题 需要打开插件大礼包(react-scripts)
npm run eject
再注意:
打开插件大礼包之前执行一次本地git仓库的提交
npm start 跳转到实例界面项目就算创建ok
#### 基本指令
npm start 本地开发环境运行
npm run eject 解开插件包
npm run build 编译打包
##### 基本目录结构
build 打包后的文件目录
config 项目的配置目录
public 静态资源目录
script js启动脚本
src 项目的源码目录
.gitignore git上传的忽略文件
package.josn
组件创建和分类
#### 组件的创建
15版本 createClass 方法
// 过期版本的创建组件方法
// let App = React.createClass({
// render() {
// return(
// <div>
// 这里是app组件
// </div>
// )
// }
// })
16版本 通过class关键字或者函数来创建组件
#### 类组件和函数组件
1、类组件 (功能组件,智能组件)
用class 关键字创建的组件
有state值 能修改state值
能写jsx
有生命周期
class App extends React.Component{
constructor(){
super() //因为是组件是继承而来 所以要执行一下父类的构造函数
// 在构造函数里初始化state
this.state = {
name:'韩梅梅'
}
}
render(){
return(
<div>
这里16版本的组件创建方式
{this.state.name}
<button onClick={()=>{
this.setState({name:'李雷雷'})
}}>change</button>
</div>
)
}
}
2、函数组件 (ui组件,木偶组件,傻瓜组件)
用函数创建的组件
没有state 就不能修改数据
没有生命周期
只能写jsx
只能接受props 渲染界面
// 接受props数据渲染界面
function App(props){
console.log(this,props)
return(
<div>
这里是函数组件 {props.name}
</div>
)
}
### 受控组件 非受控组件
不是一种新的组件而是获取表单数据的两种方式
官方推荐使用受控组件
非受控组件 通过ref 获取表单数据
class App extends React.Component{
constructor(){
super()
}
render(){
return(
<div>
<input type="text" placeholder='user' ref='user'/>
<input type="text" placeholder='pass' ref='pass'/>
<button onClick ={()=>{
let user = this.refs.user.value
let pass = this.refs.pass.value
console.log(user,pass)
}}>login</button>
</div>
)
}
}
受控组件 将表单value 和state 里的数据进行关联
class App extends React.Component{
constructor(){
super()
this.state={
user:'123',
pass:'456'
}
}
render(){
let {user,pass} = this.state
return(
<div>
<input type="text" value={user} onChange={(e)=>{
let value = e.target.value
this.setState({user:value})
}}/>
<input type="text" value={pass} onChange={(e)=>{
let value = e.target.value
this.setState({pass:value})
}}/>
<button onClick ={()=>{
console.log(user,pass)
}}>login</button>
</div>
)
}
}
组件的一些简便写法
import React ,{Fragment,Component}from 'react'
// Fragment可以代替根元素使用 并且不会在页面上进行渲染
import './index.css'
import Son from './Son'
class App extends Component{
render(){
return(
<Fragment >
<div className='test'>
这里是跟组件
<Son></Son>
</div>
</Fragment>
)
}
}
export default App
1、Fragment
可以作为跟组件使用并且不会被渲染
2、import React ,{Fragment,Component}from 'react'
es6模块化可以按需引入
3、组件的样式需要外部引入
import './index.css'
生命周期
一. 创建初始化
getDefaultProps 初始化porps
getInitialState 初始化state
以上是15.6 的生命周期 在16版本取消 用以下的构造函数代替
constructor 初始化数据
二. 挂载
1、(废弃)componentWillmount 挂载之前
componentWillMount(){
console.log('组价将要挂载')
// console.log(this)
// console.log(this.state.name)
// console.log(this.refs.p)
// this.state.name = '李雷雷'
/*
可以获取this 数据 不能获取dom
修改数据 可以直接引起页面的改变
修改数据 不会触发运行中的生命周期
这个生命周期没啥用 更不要做网络请求
16.3版本 同步渲染 ->异步渲染(fiber-diff算法)
渲染前的生命周期可以能会被意外情况打断,生命周期会重新执行
在这个生命周期放网络请求 会导致请求的多次发出
该生命周期17版本后会被废弃 现阶段是不安全的生命周期
UNSAFE_componentWillMount(){}
*/
}
2、componentDidMount 挂载结束
componentDidMount(){
console.log('挂载结束')
console.log(this)
console.log(this.state.name)
console.log(this.refs.p)
// this.state.name = '李雷雷'
this.setState({name:'李雷雷'})
/*
有dom 有数据
可以做网络请求 做初始化的操作 初始化swiper better-scroll
数据的修改不能直接引起页面的改变 需要通过setState
数据的修改会触发运行中的生命周期
*/
}
三. 更新
1、(废弃)componentWillReceiveProps props发生改变的时候触发
componentWillReceiveProps(props){
//监听props 发生改变
//参数里是更新之后的数据
//this 里是更新之前的数据
console.log('props发生改变')
console.log('this',this.props)
console.log('参数props',props)
}
2、shouldComponentUpdate 数据的改变是否应该引起页面的更新
shouldComponentUpdate(props,state){
console.log('数据变了')
// console.log('参数',props,state)
// console.log('this',this.props,this.state)
// if(this.state.name === state.name){
// return false
// }else{
// return true
// }
/*
该生命周期控制 数据修改是否要更新界面 通过该生命周期减少无关的页面更新
返回 true 更新
返回 false 不更新
参数 props 和state 将要更新的数据
this里的props和state 指的是还没更新的数据
*/
}
3、(废弃)componentWillUpdate 组件将要更新
componentWillUpdate(){
/*
页面更新之前触发
数据 dom 元素都是更新之前的
也是在render前,该生命周期也将要被废弃
*/
console.log('更新之前')
// console.log(this)
// console.log(this.state)
// console.log(this.refs.p)
// console.log(this.refs.p.innerText)
}
4、componentDidUpdate 组件更新完毕
componentDidUpdate(){
/*
在跟新操作结束之后触发
数据和dom 都是修改之后的
小心在这里做数据更新的操作
*/
console.log('更新结束')
console.log(this)
console.log(this.state)
console.log(this.refs.p)
console.log(this.refs.p.innerText)
}
四. 卸载销毁
componentWillUnMount 解除事件绑定
componentDidMount(){
window.addEventListener('scroll',this.scroll)
}
scroll=()=>{
console.log('滚滚滚')
let r =Math.random()*255
let g =Math.random()*255
let b =Math.random()*255
let a =Math.random()
this.setState({color:`rgba(${r},${g},${b},${a})`})
}
componentWillUnmount(){
console.log('组件销毁')
window.removeEventListener('scroll',this.scroll)
}
路由
一、手写路由
{/* 控制地址栏改变 */}
<Link to='/singer'>歌手</Link>
<Link to='/recommend'>推荐</Link>
{/* 控制组价的渲染 */}
<Route path='/singer' component={Singer}></Route>
<Route path='/recommend' component={Recommend}></Route>
二、路由插件 react-router
1 - 3版本 :react-router
4 - 5版本 :react-router-dom react-router-native
下载安装
npm install react-router-dom
三、路由的基本使用
引入
import {HashRouter,BrowserRouter,NavLink,Link,Route,Switch,Redirect} from 'react-router-dom'
A、组件的父容器,所有的路由组件都要放到里面
1、HashRouter 哈希路由
2、BrowserRouter 历史路由(刷新404问题)
B、控制地址栏的改变
1、Link
2、NavLink
注意:exact 属性路径和地址栏路径完全匹配
注意:普通的组件内部是没有路由对象的 被路由处理过的组件才有路由对象
1、to(exact) 要跳转的组件路径
exact to='/singer'
2、to={ {
pathname: "/singer",
search: "?sort=name",
hash: "#the-hash",
state: { fromDashboard: true }
} }
路由跳转后所有的属性 都可以在目标组件的props里进行接收
以下属性只有NavLink有
3、activeClassName 路由激活时的样式
activeClassName='selected'
C、根据地址栏改变渲染不同的组件
注意
router-view 只能显示一个组件 route路径匹配几个显示几个
exact 地址栏路径必须和path完全一致
Route
属性
1、path(exact) 渲染的组件路径
exact path='/singer'
2、component 渲染的组件
component={Singer}
component={(props)=>{
return(
<div>
这是函数创建的组件
</div>
)
}}
写法和上面一样,优先级不同(render>children>component),不能同时写
3、render
4、children
D、其他内置组件
1、Switch 百里挑一 只返回第一个匹配到的组件
<Switch>
<Route exact path='/singer' component={Singer}></Route>
<Route path='/recommend' component={Recommend}></Route>
<Route path='/singer/test' component={SingerTest}></Route>
{/* 404页面,要放到最后才匹配 */}
<Route component={NotFound}></Route>
</Switch>
2、Redirect 重定向
<Switch>
{/* 小心产生死循环 */}
<Redirect exact from='/' to ='/recommend'></Redirect>
<Route exact path='/singer' component={Singer}></Route>
<Route path='/recommend' component={Recommend}></Route>
<Route path='/singer/test' component={SingerTest}></Route>
<Route component={NotFound}></Route>
</Switch>
四、编程式导航和声明式导航(寻找路由对象)
<Link><NavLink>实现路由的跳转 是声明式导航
通过js路由对象的方式叫做编程式导航
1、push 跳转到,能返回
this.props.history.push
2、replace 跳转到,不能返回
3、go
4、goBack
5、goForwd
注意 :正常创建的组件是没有路由对象的
1. 通过Route 处理过的组件在props里有路由对象
2. 通过withRouter 处理过的组件也有路由对象
let NewComponent =withRouter(CustomNav)
// withRouter是一个函数 接受一个组件作为参数
// 返回一个新的组件 在新的组件的props里会被注入路由对象
// withRouter的作用处理一个组件给处理的组件添加路由对象
export default NewComponent
五、路由传参
1、动态导航 /hehe/:id
this.props.history.push(`/singer/${us}/${ps}`)
在路由对象的match.params 里获取传递的参数
2、query传参 /hehe?us=123&ps=123
相当于get方法 接受数据在路由对象的 location.search里 需要自己做字符串解析
this.props.history.push(`/recommend?us=${us}&ps=${ps}`)
3、state传参
在路由对象的location.state里接收参数
this.props.history.push({pathname:'/recommend',state:{要传递的数据}})
六、嵌套路由
在路由里套路由 所有的组价你都可以使用使用 Link Switch ..
嵌套路由的上一级 千万不能加精准匹配
写法一:在一级路由组件定义中嵌套
function My (){
console.log('我的组件')
return(
<div>这里是我的组件
<Link to='/my/info'>我的信息</Link>
<Link to='/my/login'>我的登录</Link>
<Route path='/my/info' component={Info}></Route>
<Route path='/my/login' component={Login}></Route>
</div>
)
}
写法二:
<Route path='/my' render={()=>{
return(
<div>
<h3>我的组件</h3>
<hr/>
<Link to='/my/info'>我的信息</Link>
<Link to='/my/login'>我的登录</Link>
<Route path='/my/info' component={Info}></Route>
<Route path='/my/login' component={Login}></Route>
</div>
)
}}>
</Route>
高阶组件
hoc 本质是一个函数 接受一个组件作为参数 返回一个新的组件
作用:功能性的封装 减少重复代码
一般被高阶组件处理过的组件获取数据 都从props获取
import React, { Component, Fragment } from 'react';
export default (TmpComponent)=>{
//TmpComponent参数传递的组件
// 创建一个新的组件
class NewComponent extends Component {
constructor(){
super()
this.state={
name:'数据加载ing'
}
}
componentDidMount(){
setTimeout(()=>{
let name= localStorage.getItem('name')
this.setState({name})
},1000)
}
render() {
return (
<Fragment>
<TmpComponent name={this.state.name}></TmpComponent>
</Fragment>
);
}
}
// 返回创建的新组件
return NewComponent
}
react的全局状态管理 redux
安装redux
npm install redux
比喻
光绪皇帝 store 传递奏折 发布政令
老佛爷 reducer 接受奏折 根据奏折修改数据
平民百姓 component 使用数据 修改数据并监听更新数据
文武百官 actionCreator 提交奏折给老佛爷
一、redux 基本使用
1、创建 store 并且和 reducer 关联
import {createStore} from 'redux'
import reducer from './reducer'
let store = createStore(reducer)//创建全局状态管理对象
export default store
2、创建reducer
reducer 是一个函数,能接受2个参数
参数1 修改前的数据 prevState
参数2 就是奏折 actions
批奏折 就是根据奏折actions 去修改数据
将修改后的数据 newData 返回给store
let State={
name:'韩梅梅',
age:16
}
// prevState 代表修改前的数据 = 付一个初始值默认值
export default (prevState = State,actions)=>{
let newData = prevState
// 修改数据
let {type,payload} = actions
switch (type) {
case 'CHANGE_NAME':
newData.name = payload
break;
case 'CHANGE_AGE':
newData.age = payload
break;
default:
break;
}
// 返回修改后的数据
return newData
}
3、创建actionCreator
本质是一个对象 对象里有一堆的函数
在内部的函数
a. 创建action 也是一个对象必须有type
b. store.dispatch(action) 提交action给reducer
import Store from './store'
export default{
changeName(){
// 创建一个action
let action={
type:'CHANGE_NAME', //type是必须的告诉reducer要修改那一条数据
payload:'隔壁老王'
}
// 发送奏折 将action 提交给reducer
Store.dispatch(action)
},
changeAge(age){
let action={
type:'CHANGE_AGE',
payload:age
}
Store.dispatch(action)
}
}
reducer根据 参数1修改前的数据和参数2 actions 对数据进行修改 并且返回修改后的数据
4、在组件中使用
a.引入store、actionCreator
b.使用store下的getState方法,getState方法获取的值就是reducer返回的值(所以reducer的state一定要有初始值)
获取全局状态值 let {name,age} = Store.getState()
c、使用actionCreator里定义的方法来修改数据,用Store.subscribe()监听全局状态值发生改变
componentDidMount(){
// 监听全局状态值发生改变
Store.subscribe(()=>{
// 只要该回调执行了 那就说明全局状态值发生改变需要修改页面
传空对象全部更新
this.setState({})
})
}
注意:redux有时可用高阶组件hoc来优化
二、redux 模块化
使用combineReducers方法实现redux的模块化
import {createStore,combineReducers} from 'redux'
import todolist from './reducer'
let reducer = combineReducers({todolist})
export default createStore(reducer)
注意:模块化后取值要添加模块名
let {list} = store.getState().todolist
三、redux 异步处理
将网络请求放到actionCreator里
1. 减少重复的代码 统一管理api接口
2. 时间旅行 更精准的检测到全局状态值的变化
addlist(msg){
setTimeout(()=>{
store.dispatch({
type:'ADD_LIST',
hehe:msg
})
},1000)
},
react-redux
优化模块 优化redux的使用过程
下载安装
npm install react-redux
一、基本使用
1、通过react-redux 提供的provider提供器 将全局状态对象挂载到根元素的上下文上
import {Provider} from 'react-redux'
import store from './store/store.js'
ReactDOM.render(
// Provider 将全局状态对象store 挂载到跟组件的上下文上
// 挂载之后所有的子组件都可以访问跟组件的上下文
// store 属性固定
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root'));
2、在组件中共享全局状态值
通过react-redux 提供的connect 从跟组件的上下文上获取store对象
通过高阶组件将获得到的store传给目标组件的props
import {connect} from 'react-redux'
connect 本质是一个方法 返回一个高阶组件
connect()(处理的组件)
conenct 方法有2个参数
参数1叫mapStateToProps
参数2叫mapDispatchToProps
参数1 mapStateToProps 将全局状态值映射到props里
本质也是一个函数
特点1 该函数接受全局状态值作为参数
特点2 该函数返回的数据会被映射到当前组件的props里
// let mapStateToProps =(state)=>{
// console.log('mapStateToProps',state)
// return state
// }
参数2 mapDisPatchToProps 作用就是将dispatch 映射到props里
mapDisPatchToProps 本质也是一个函数
1.可以接dispatch 作为参数
2.return的对象也会映射到props里
mapDispatchToProps 如果为空 将dispath 映射到props里
如果不为空 将return的对象映射到props里
// let mapDispathcToProps=(dispatch)=>{
// // console.log(dispatch)
// // return{
// // fun1(){
// // console.log('fun1')
// // let action = ActionCreatore.CHANGE_AGE()
// // dispatch(action)
// // }
// // }
// return bindActionCreators(ActionCreatore,dispatch)
// }
import {bindActionCreators} from 'redux'
最后导出时用connect处理组件
export default connect(state=>state,dispatch=>
bindActionCreators(ActionCreatore,dispatch))(Son);
3、在组件中使用数据和修改数据
通过connect已经把全局状态挂载到组件的props里
A、使用数据
let {name,age} = this.props
B、修改数据
<button onClick={this.props.CHANGE_AGE}>改名</button>
二、其他文件对应的写法
1、reducer
使用react-redux,处理数据前要进行一次深拷贝
let newData = JSON.parse(JSON.stringify(prevState))
/*
1.修改引用类型的数据的时候 会导致修改到原数据
2.新数据和老数据对比 发现没有变化 页面不更新
*/
2、actionCreator + actionTypes
A、actionTypes文件里放action的type
// 项目复杂状态值比较多的时候容易发生混乱
export const CHANGE_NAME = "CHANGE_NAME"
export const CHANGE_AGE = "CHANGE_AGE"
B、actionCreator文件里type和方法名使用变量
import {CHANGE_NAME,CHANGE_AGE}from './actionType'
export default {
[CHANGE_NAME](){
let action={
type:CHANGE_NAME,
payload:'李雷雷'
}
return action
},
[CHANGE_AGE](){
let action={
type:CHANGE_AGE,
payload:88
}
return action
}
}
三、react-redux中的异步操作action
解决方式通过异步中间件 redux-thunk redux-sage redux-promise
1. 安装异步插件 npm install redux-thunk
2. 在store.js 引入并使用(applyMiddleware + redux-thunk)
import {createStore,applyMiddleware} from 'redux'
import thunk from 'redux-thunk' //解决异步的插件
import reducer from './reducer'
export default createStore(reducer,applyMiddleware(thunk))
3、除了actionCreator 需要修改之外 其他的都不用动
a. 如果是同步的方法也不需要动 返回action
b. 如果action里有异步 返回一个函数 函数能接受dispath 在函数内部 做网络请求,成功之后通过dispath手动的发送
//异步的写法
[CHANGE_NAME](){
//dispatch 是connect 传递过来的
return(dispatch)=>{
setTimeout(()=>{
let action ={
type:CHANGE_NAME,
payload:'半藏'
}
dispatch(action)
},1000)
}
},
注意:
setState 是个异步
但是如果setState放到了异步中,就变成同步了
react补充
一、路径起别名
找到webpack配置,并且修改alias配置即可
resolve: {
alias: {
'@api': path.join(__dirname, '../src/api'),
}
},
二、关于样式
react脚手架创建项目自带sass,less需要另外安装
1. 安装相关的预处理语言与加载器
npm install less less-loader -D
2. 修改配置文件 config/webpack.config.js 将sass相关全变成less
3. 改完配置文件后重启
2、样式作用域问题(样式模块化)
A、 import './index.less' 全局引入
B、 import HEHE from './index.module.less' 局部引入
<div className={HEHE.类名}>
三、路由懒加载(安装react-loadable)
封装成一个高阶组件
import React from 'react'
import LoadAble from 'react-loadable'
// 过度组件
function LogingComponent (){
return(
<div>这里是过度组件</div>
)
}
export default (LoadComponent)=>{
return LoadAble({
loader:LoadComponent,
loading:LogingComponent
})
}

浙公网安备 33010602011771号