react学习
GeGeZZ -react框架库
react-router
路由pubsub
消息管理redux
状态管理ant-design
UI库要点jsx
最后翻译过来就是React.createElement
方法
createElement(element,options,content)
elment
元素名称
options
属性对象
content
属性里面的内容
demo: createElement('h1',{id:'test'},'hello react')
jsx注意事项
变量用一个大括号括起来;如果引用class
样式,需要用className
定义的jsx
不需要引号,如果有多层,用小括号括起来内联样式style
要用对象的形式,且属性要用驼峰命名只允许一个根标签标签必须闭合自定义组件以大写字母开头
const name='zhangsan'
const Rdom=(
<div>
<h1 className='test' style={{fontSize:'20px'}}>{name}<h1>
<h1 className='test' style={{fontSize:'20px'}}>{name}<h1>
</div>
)
react
创建函数组件
引用需要用标签,且标签要有闭合
function Demo(){
return <h1>demo test</h1>
}
ReactDOM.render(<Demo/>,document.getElementById('test'))
react
创建类组件
React.Component
类组件里面必须定义render
方法,并且需要返回值调用组件,渲染到页面,组件是命名是大写开头调用组件会new
一个组件,然后调用render
方法,且类里面this
指向的是组件创建的实力对象,也叫组件实力对象。class MyComponent extends React.Component{
render(){
return (
<h1>test</h1>
)
}
}
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
react
事件以及state
1.节点绑定事件需要用on
+事件名,需要驼峰命名
2.事件的回调函数需要用bind
重新绑定,否则this
会丢失,或者用箭头函数赋值给属性,绑定该属性
3.state
对象里面需要定义需要变化的状态(属性)
4.更改state
里面的状态,需要用this.setState
方法
5.自定义方法需要用箭头函数赋值给属性,或者用bind
方法绑定this
class ChangeWeather extends React.Component{
constructor(){
super()
this.state={
flag:true
}
this.changeFlag=this.changeFlag.bind(this)
}
render(){
const {flag}=this.state
return (
<h1 onClick={this.changeFlag}>今天天气很{flag?'好':'不好'}</h1>
)
}
changeFlag(){
this.setState({
flag:!this.state.flag
})
}
}
ReactDOM.render(<ChangeWeather/>,document.getElementById('test'))
//上面例子精简版
class ChangeWeather extends React.Component {
state = { flag: true }
render() {
const { flag } = this.state
return (
<h1 onClick={this.changeFlag}>今天天气很{flag ? '好' : '不好'}</h1>
)
}
changeFlag = () => {
this.setState({
flag: !this.state.flag
})
}
}
ReactDOM.render(<ChangeWeather />, document.getElementById('test'))
react
里面的props
1.通过标签传递属性,可以通过扩展运算符进行传递
2.组件里面通过props
引用
3.如果是变量需要用大括号的形式进行传递
class ChangeWeather extends React.Component{
render (){
return (
<div>
{this.props.title}
{this.props.age}
{this.props.obj.test}
{this.props.test}
</div>
)
}
}
const obj={
test:123
}
ReactDOM.render(<ChangeWeather title="title" age={18} obj={obj} {...obj}/>, document.getElementById('test'))
props
的属性限制以及默认值
1.16.x版本之前是用React.propsType.xxxx
进行限制,之后的版本是需要引入propstype.js
,然后再类的propTypes
属性上面进行定义
2.限制属性的时候,直接定义到类上面进行限制
3.如果是函数限制传的类型为func
,而不是function
4.如果没有传值,需要给默认值,需要再类的defaultProps
属性上面进行定义默认值
5.定义的这些规则需要咋渲染之前进行定义
6.定义的属性规则也可以用静态属性进行定义static
//直接定义到类上面
class ChangeWeather extends React.Component{
render (){
return (
<div>
{this.props.title}
{this.props.age}
{this.props.obj.test}
{this.props.test}
</div>
)
}
}
//需要再渲染之前进行规则定义,在类的propTypes上面进行定义
ChangeWeather.propTypes = {
title: PropTypes.string.isRequired,
fun:PropTypes.func.isRequired//函数要用func这个类型
}
//默认值需要再类的defaultProps属性上面进行定义
ChangeWeather.defaultProps={
title:"fdsaf",
fun:function(){}
}
const obj={
test:123,
}
ReactDOM.render(<ChangeWeather title="test" age={18} obj={obj} {...obj}/>, document.getElementById('test'))
//用静态属性的方式
class ChangeWeather extends React.Component {
static propTypes = {
title: PropTypes.string.isRequired,
fun: PropTypes.func.isRequired
}
static defaultProps = {
title: "fdsaf",
fun: function () { }
}
render() {
return (
<div>
{this.props.title}
{this.props.age}
{this.props.obj.test}
{this.props.test}
</div>
)
}
}
const obj = {
test: 123,
}
ReactDOM.render(<ChangeWeather title="test" age={18} obj={obj} {...obj} />, document.getElementById('test'))
react
里面的ref
1.在节点里面通过ref
属性进行绑定
2.在逻辑里面通过refs
接受
3.接受的ref
是一个真实节点
class Test extends React.Component{
render(){
return (
<div>
<input ref="input1" type="text"/>
<button onClick={this.btnClick}>点击</button>
</div>
)
}
btnClick=() => {
const {input1}=this.refs
alert(input1.value)
}
}
ReactDOM.render(<Test/>,document.getElementById('test'))
4.ref
通过回调方式获取
/* ref 回调函数的形式 */
class Reftest extends React.Component{
inputel=null
btnClick=() => {
alert(this.inputel.value)
}
render(){
return (
<div>
<input type="text" ref={(el)=>{this.inputel=el}}/>
<button onClick={this.btnClick}>点击 </button>
</div>
)
}
}
ReactDOM.render(<Reftest/>,document.getElementById('test'))
ref
如果用内联的方式进行获取,在数据更新的 时候会调用两次回调函数,第一次会给回调函数传null
第二次会传当前的节点。解决办法为直接用绑定的回调函数。只会调用一次回调函数,不会调用多次。但是内联和绑定的方式不会有任何影响。开发中一般用内联的方式进行开发。ref
的创建方式三,通过React.createRef
的方式创建。该函数调用后会返回一个对象,key
为current
的对象,值为节点。有多少个ref
就要调用几次前面的函数。官方推荐写法
/* ref React.createRef的方式 */
class Test extends React.Component{
//有多少个就要创建多少个
refstest=React.createRef();
btnclick=()=>{
console.log(this.refstest.current.value);
}
render(){
return (
<div>
//这里了是需要绑定上面返回的属性
<input ref={this.refstest} type="text"/>
<button onClick={this.btnclick}>点击</button>
</div>
)
}
}
ReactDOM.render(<Test/>,document.getElementById('test'))
react
的非受控组件所有的表单组件现用现取的组件。取值需要用到ref
react
的受控组件
所有的输入框的值都存到状态里面,类似vue
的双向绑定
/* 受控组件*/
class Test extends React.Component {
state = {
name: ''
}
getTestValue = (e) => {
this.setState({
name: e.target.value
})
}
handleClick = () => {
console.log(this.state.name);
}
render() {
return (
<div>
<input type="text" onChange={this.getTestValue} />
<button onClick={this.handleClick}>点击</button>
</div>
)
}
}
ReactDOM.render(<Test />, document.getElementById('test'))
函数的柯力化以及高阶函数
1.高阶函数:
1.1函数返回一个函数
1.2 函数传参,该参数为一个函数
2.柯力化函数:
2.1函数返回函数,最后返回的函数一起处理前面函数的参数。
class Test extends React.Component {
state = {
name: ''
}
getTestValue = (name) => {
return (event) => {
console.log(name,event);
}
}
handleClick = () => {
console.log(this.state.name);
}
render() {
return (
<div>
<input type="text" onChange={this.getTestValue('test')} />
<button onClick={this.handleClick}>点击</button>
</div>
)
}
}
ReactDOM.render(<Test />, document.getElementById('test'))
react
的声明周期
ReactDOM.unmountComponentAtNode(el)
卸载组件
//只要一获取值就销毁组件
class Test extends React.Component {
getValue(key, e) {
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
render() {
return (
<div>
<input type="text" onChange={(e) => { this.getValue('userName', e) }} />
</div>
)
}
}
ReactDOM.render(<Test />, document.getElementById('test'))
react
组件生命周期
1.componentDidMount
//组件挂在时调用,只调用一次
2.componentWillUnmount //组件即将销毁
/* 组件生命周期演示 */
class Test extends React.Component {
state = {
count: 1
}
timer = null;
render() {
const { count } = this.state;
return (
<div>
<div> 数字:{count}</div>
<div onClick={this.removeTimer}>点击我</div>
</div>
)
}
// 组件挂载
componentDidMount() {
this.timer = setInterval(() => {
let { count } = this.state;
count += 1;
this.setState({
count,
})
}, 200)
}
// 组件即将卸载
componentWillUnmount() {
clearInterval(this.timer)
}
removeTimer = () => {
// 移除当前组件
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
}
ReactDOM.render(<Test />, document.getElementById('test'))
子组件生命周期执行顺序
constructor
componentWillMount
render
componentDidMount
componentWillUnmount
getSnapshotBeforeUpdate
//初始化的声明周期执行顺序
class Demo extends React.Component {
constructor(props) {
super(props)
console.log('constructor');
this.state = {
count: 1
}
}
componentWillMount() {
console.log('componentWillMount');
}
componentWillUnmount() {
console.log('componentWillUnmount');
}
render() {
console.log('render');
const { count } = this.state
return (
<div>
<div>展示的count:{count}</div>
<div onClick={this.btnClick}>点击我</div>
<div onClick={this.remove}>卸载组件</div>
</div>
)
}
remove = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
btnClick = () => {
let { count } = this.state
count += 1;
this.setState({
count,
})
}
}
ReactDOM.render(<Demo />, document.getElementById('test'))
class A extends React.Component{
state={
count:1
}
render(){
console.log('render');
const {count}=this.state
return (
<div>
<B name={count}/>
<div>count {count}</div>
<div onClick={this.btnClick}>点击我</div>
</div>
)
}
// 跟新的时候会走这个生命周期,必须要返回true或者false,若返回false就不会执行后面的声明周期
shouldComponentUpdate(){
console.log('shouldComponentUpdate');
return true
}
componentWillUpdate(){
console.log('componentWillUpdate');
}
componentDidUpdate(){
console.log('componentDidUpdate');
}
btnClick=() => {
let {count}=this.state
count+=1;
this.setState({
count ,
})
}
}
class B extends React.Component{
//父组件传递的props更新了才会调用这个生命周期,初次不会调用该生命周期
componentWillReceiveProps(){
console.log('componentWillReceiveProps');
}
render(){
return (
<div>{this.props.name}</div>
)
}
}
ReactDOM.render(<A />, document.getElementById('test'))
class Demo extends React.Component {
state = {
arr: []
}
componentDidMount() {
setInterval(() => {
const { arr } = this.state;
this.setState({
arr: ['新闻' + (arr.length + 1), ...arr]
})
}, 1000)
}
// 新的声明周期,在更新前执行,可以像componentDidUpdate声明周期里面传递一个参数
getSnapshotBeforeUpdate() {
return this.refs.list.scrollHeight
}
componentDidUpdate(prepops, prestates, scrollheight) {
console.log(this.refs.list.scrollHeight, '...', scrollheight);
this.refs.list.scrollTop += this.refs.list.scrollHeight - scrollheight
}
render() {
return (
<div>
<div className="list" ref="list">
{
this.state.arr.map((item, index) => {
return (
<div key={index} className="li">{item}</div>
)
})
}
</div>
</div>
)
}
}
ReactDOM.render(<Demo />, document.getElementById('test'))
react diff
算法
dom
通过key
值去判断是否存在相同的值,如果key
值相同,判断对应的内容是否相同,若内容相同复用原来的dom
,如果不相同,创建新的dom
渲染到页面,如果key
值不相同直接生成dom
渲染到页面使用index
作为key
值存在的问题:可能会使效率低下(旧dom
可能复用不了),页面错位(若数据存在逆反操作)。react
脚手架
1.全局安装npm i -g create-react-app
2.进入要创建项目的目录控制台执行create-react-app projectName
即创建成功
样式模块化
1.利用文件名XXX.module.css
,引入方式import hello from './xxx.module.css'
在用的地方用hello.className
的形式进行
2.利用less
进行嵌套
react
组件父子通信
1.父传子利用props
进行传递
2.子传父利用props
给子组件传递函数,子组件通过props
接收该函数,然后调用,且可以传值。
解决跨域
利用package.json
的proxy
字段进行代理。请求的时候用本地的域名加端口号加接口名进行请求
//pageage.json
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"proxy":"http://localhost:5000"
//请求的地址,端口号为本地的3000,3000代理到服务器为端口号5000的服务器
axios.get('http://localhost:3000/students')
.then((res) => {
console.log(res.data)
})
}
2.在项目目录src/下新建setupProxy.js文件,然后写入如下代码:
const proxy = require('http - proxy - middleware');
module.exports = function (app) {
app.use(proxy('/api', {
target: 'http://localhost:5000',
secure: false,
changeOrigin: true,
pathRewrite: {
"^/api": ""
},
}));
};
兄弟组件之间的通信,利用pubsubjs
安装pubsub-js
yarn add pubsub-js
引入pubsubjs
并在传递数据的组件中进行消息发布,在需要获取数据的组件中进行消息订阅
componentDidMount() {
this.id=Pubsub.subscribe('getData', (name, stateObj) => {
this.setState(stateObj)
})
}
componentWillUnmount(){
pubsub.undescribe(this.id)
}
request=()=>{
axios.get(
'http://localhost:3000/xxx'
)
.then((res) => {
Pubsub.publish('getData',{
loading: false,
users: res.data.items,
err:false
})
})
.catch((err) => {
Pubsub.publish('getData',{
loading: false,
err:err.message
})
})
}
react
路由
1.安装react-router-dom
yarn add react-router-dom
引入必要组件
import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import About from './components/About'
import Home from './components/Home'
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{/* <a className="list-group-item active" href="./about.html">About</a>
<a className="list-group-item" href="./home.html">Home</a> */}
<Link to="/about" className="list-group-item">About</Link>
<Link to="/home" className="list-group-item">Home</Link>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{/* <h3>我是About的内容</h3> */}
<Route path='/about' component={About}/>
<Route path='/Home' component={ Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom'
import './index.css';
import App from './App';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
通过this.props.children
可以获取标签体内容switch
组件包裹路由只会匹配第一个匹配到 的路由进行渲染对应组件react
多级路由导致样式丢失问题
public
文件下的index.html
文件引入文件路径修改为/
绝对路径的这种形式,或者用%PUBLIC_URL%
这种形式进行引入。或者将BrowserRouter
组件换成HashRouter
组件`Router
组件中的exact`属性用于精准匹配路由
<Route exact path='/home' component={Home} />
Redirect
组件用于没有匹配到路径的时候,调转到默认路由,一般放到注册组件最后Switch
组件用于匹配到第一个路由就不往后面进行匹配NavLink
用于路由高亮显示,可以自定义className
Link
用于路由跳转
<Switch>
<Route path='/about/about' component={About} />
<Route exact path='/home' component={Home} />
<Redirect to="/home"></Redirect>
</Switch>
嵌套路由
1.子组件注册组件需要带上父组件的path
import React, { Component } from 'react'
import { Switch, Route ,Redirect} from 'react-router-dom'
import About from './pages/About'
import Home from './pages/Home'
import MyNavLink from './components/MyNavLink'
import './App.css'
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
<MyNavLink to="/about" >About</MyNavLink>
<MyNavLink to="/home" >Home</MyNavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
<Switch>
<Route path='/about' component={About} />
<Route path='/home' component={Home} />
<Redirect to="/home"></Redirect>
</Switch>
</div>
</div>
</div>
</div>
</div>
)
}
}
子组件import React from "react";
import Message from "./Message";
import News from "./News";
import MyNavLink from "../../components/MyNavLink";
import { Switch, Route,Redirect } from 'react-router-dom'
export default class Home extends React.Component {
render() {
console.log(this.props);
return (
<div>
<h2>Home组件内容</h2>
<div>
<ul className="nav nav-tabs">
<li>
<MyNavLink to="/home/news">News</MyNavLink>
</li>
<li>
<MyNavLink to="/home/message">message</MyNavLink>
</li>
</ul>
<Switch>
<Route path="/home/news" component={News}></Route>
<Route path="/home/message" component={Message}></Route>
<Redirect to="/home/message"></Redirect>
</Switch>
</div>
</div>
)
}
}
路由组件传参
params
传参
1.跳转的地方需要进行参数按顺序传递
2.注册的地方需要进行按顺序进行接收
3.子组件通过this.props.match.params
获取
import React, { Component } from 'react'
import { Route } from 'react-router';
import { Link } from 'react-router-dom';
import MsgDetail from './MsgDetail';
export default class Message extends Component {
state = {
students: [{
id: 1,
name: '张三',
age: 12
}, {
id: 2,
name: '李四',
age: 13
}, {
id: 3,
name: '王二',
age: 14
}]
}
render() {
const { students } = this.state;
return (
<div>
<ul>
{
students.map((item) => {
return (
<li>
<Link to={`/home/message/msgdetail/${item.name}/${item.age}`} key={item.id}>{item.name}</Link>
</li>
)
})
}
</ul>
<hr />
<Route path='/home/message/msgdetail/:name/:age' component={MsgDetail}/>
</div>
)
}
}
4.子组件进行获取
import React, { Component } from 'react';
class MsgDetail extends Component {
render() {
console.log(this.props);
const { name, age } = this.props.match.params;
return (
<div>
{name}----{ age}
</div>
);
}
}
export default MsgDetail;
search
传参(类似vue
里面的query
)
1.在跳转的地方进行传递
2.在子组件的this.props.location.search
进行取值
3.需要将search
参数进行转换成对象的形式
import React, { Component } from 'react'
import { Route } from 'react-router';
import { Link } from 'react-router-dom';
import MsgDetail from './MsgDetail';
export default class Message extends Component {
state = {
students: [{
id: 1,
name: '张三',
age: 12
}, {
id: 2,
name: '李四',
age: 13
}, {
id: 3,
name: '王二',
age: 14
}]
}
render() {
const { students } = this.state;
return (
<div>
<ul>
{
students.map((item) => {
return (
<li>
<Link to={`/home/message/msgdetai?name=${item.name}&age=${age}`} key={item.id}>{item.name}</Link>
</li>
)
})
}
</ul>
<hr />
<Route path='/home/message/msgdetail' component={MsgDetail} />
</div>
)
}
}
4.子组件进行获取
import React, { Component } from 'react';
import qs from 'querystring'
class MsgDetail extends Component {
render() {
console.log(this.props);
const { search } = this.props.location.search
const { name,age}=qs.parse(search.slice(1))
return (
<div>
{name}----{ age}
</div>
);
}
}
export default MsgDetail;
state
传参
1.路由跳转的地方需要通过对象的方式进行传递,需要包含path
以及state
属性。state
属性是一个对象
2.子组件通过this.props.locaiton.state
进行获取
3.state
传递的参数在地址栏上面是看不到的,上面的两种都是在地址栏上面看的到的。
import React, { Component } from 'react'
import { Route } from 'react-router';
import { Link } from 'react-router-dom';
import MsgDetail from './MsgDetail';
export default class Message extends Component {
state = {
students: [{
id: '00122',
name: '张三',
age: 12
}, {
id: '00233',
name: '李四',
age: 13
}, {
id: '003432423',
name: '王二',
age: 14
}]
}
render() {
const { students } = this.state;
return (
<div>
<ul>
{
students.map((item) => {
return (
<li key={item.id}>
<Link to={{ path: '/home/message/msgdetail', state: { name: item.name, age: item.age } }}>{item.name}</Link>
</li>
)
})
}
</ul>
<hr />
<Route path='/home/message/msgdetail' component={MsgDetail} />
</div>
)
}
}
4.子组件进行接收
import React, { Component } from 'react';
import qs from 'querystring'
class MsgDetail extends Component {
render() {
console.log(this.props);
const { name,age}=this.props.location.state
return (
<div>
{name}----{ age}
</div>
);
}
}
export default MsgDetail;
编程式组件导航
通过this.props.history
的api
进行跳转
jump = (name,age) => {
this.props.history.push('/home/message/msgdetail', { name, age } )
}
withRouter
若想在一般组件中使用路由跳转的api
可以引入withRouter
方法
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
class Header extends Component {
goBack = () => {
this.props.history.goBack()
}
goFowrd = () => {
this.props.history.goForward()
}
render() {
return (
<div className="page-header">
<h2>React Router Demo</h2>
<button onClick={this.goBack}>回退</button>
<button onClick={this.goFowrd}>前进</button>
</div>
)
}
}
export default withRouter(Header)
antd
按需引入,可参考地址https://3x.ant.design/docs/react/use-with-create-react-app-cn
中的高级配置redux
1.安装redux
yarn add redux
2.创建redux
文件夹,在该文件下创建store
文件,action
文件,reducer
文件,constent
文件
3.store.js
import { createStore } from "redux";
import countRedux from './count_redux'
export default createStore(countRedux)
4.count_action.js
import {ADD,DESC } from './constent'
export const add = (data) => ({
type: ADD,
data
})
export const desc = (data) => ({
type: DESC,
data
})
5.count_redux.js
import { ADD,DESC} from './constent'
export default function (preState=0, action) {
const { type,data}=action
switch (type) {
case ADD:
return preState + data
case DESC:
return preState - data
default:
return preState
}
}
6.constent.js
export const ADD='add'
export const DESC='desc'
7.index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App.js";
import store from './redux/store'
ReactDOM.render(<App></App>, document.getElementById('root'))
store.subscribe(() => {
ReactDOM.render(<App></App>, document.getElementById('root'))
})
异步action
1.引入并安装redux-thunk
2.利用中间件传入thunk
3.action
返回的是一个函数,该函数会带有dispatch
函数参数
代码如下:
store.js
import { createStore, applyMiddleware } from "redux";
import countRedux from './count_redux'
import thunk from 'redux-thunk'
export default createStore(countRedux, applyMiddleware(thunk))
action.js
export const addAsync = (data, time) => {
//返回一个带有dispatch的参数的函数
return (dispatch) => {
setTimeout(() => {
dispatch(add(data))//调用同步action
},time)
}
}
react-redux
1.引入并安装
yarn add react-redux
2.创建容器组件,用于操作状态以及包裹ui
组件(链接ui
组件以及redux
)
// 引入要展示的UI组件
import countUi from '../../components/Count'
// 用于连接UI组件以及redux
import { connect } from 'react-redux'
// 引入action
import { add, desc, addAsync } from '../../redux/count_action'
// 将store里面的状态映射到props,可以用过UI组件进行操作(ui组件通过this.props.xxx获取)
function mapStateToProps(state) {
return {
count: state
}
}
// 将store里面的操作状态的方法映射到props,可以用过UI组件进行操作(ui组件通过this.props.xxx获取)
function mapDispatchToProps(dispatch) {
return {
add: (num) => {
dispatch(add(num))
},
desc: (num) => {
dispatch(desc(num))
},
addasync: (num, time) => {
dispatch(addAsync(num,time))
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(countUi)
通过props
传递给子组件store
UI
组件的优化写法
// 引入要展示的UI组件
import countUi from '../../components/Count'
// 用于连接UI组件以及redux
import { connect } from 'react-redux'
// 引入action
import { add, desc, addAsync } from '../../redux/count_action'
// 将store里面的状态映射到props,可以用过UI组件进行操作(ui组件通过this.props.xxx获取)
/* function mapStateToProps(state) {
return {
count: state
}
} */
// 将store里面的操作状态的方法映射到props,可以用过UI组件进行操作(ui组件通过this.props.xxx获取)
/* function mapDispatchToProps(dispatch) {
return {
add: (num) => {
dispatch(add(num))
},
desc: (num) => {
dispatch(desc(num))
},
addasync: (num, time) => {
dispatch(addAsync(num,time))
}
}
} */
// export default connect(mapStateToProps, mapDispatchToProps)(countUi)
// 优化写法
export default connect(
state => ({ count: state }),
//这里可以返回一个简单对象,内部可以自动分发action
{
add: add,
desc: desc,
addasync: addAsync
}
)(countUi)
5.引入react-redux
可以不用手动监听转态变化
import React from "react";
import ReactDOM from "react-dom";
import App from "./App.js";
// import store from './redux/store'
ReactDOM.render(<App></App>, document.getElementById('root'))
// 引入react-redux后可以不用手动监听状态变化
// // 监测redux转态改变,redux状态改变会重新渲染页面
// store.subscribe(() => {
// ReactDOM.render(<App></App>, document.getElementById('root'))
// })
6.利用react-redux
的provider
传递store
import React from "react";
import ReactDOM from "react-dom";
import App from "./App.js";
import store from './redux/store'
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider >
, document.getElementById('root'))
多个reducer
利用combineReducers
函数合并
import { createStore, applyMiddleware ,combineReducers } from "redux";
import countRedux from './reducers/count_redux'
import person from "./reducers/person";
import thunk from 'redux-thunk'
export default createStore(
// 多个reducer用combineReducers合并
combineReducers({
count: countRedux,
person: person,
}),
applyMiddleware(thunk)
);
reducer
必须是一个纯函数,即传入的什么参数,就返回改参数,且传入的参数不能被改写。如果传入的是对象或者是数组。返回的值也应该是一个对象或数组,不可以在原有的对象或数组中进行操作再返回
import { ADD_PERSON } from "../constent";
export default function (prestate=[],action) {
const { type, data } = action;
switch (type) {
case ADD_PERSON:
return [data,...prestate]
default:
return []
}
}
redux
配置的开发者工具
redux-devtools
在项目中安装redux-devtools-extension
在store.js
中进行如下配置
import { createStore, applyMiddleware } from "redux";
import thunk from 'redux-thunk'
import { composeWithDevTools } from "redux-devtools-extension";
import reducers from "./reducers";
export default createStore(
// 多个reducer用combineReducers合并
reducers,
composeWithDevTools(applyMiddleware(thunk))
);
打包后的文件如何在本地启动
1.全局安装serve
插件
npm install -g serve
进入打包的文件目录运行serve
命令