day3--react-redux

一、认识高阶函数和高阶组件

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0gpKJOwy-1649342396303)(img/高阶函数.png)]

2.应用–可以增加原有组件没有的props

在这里面,把home类组件变成了高阶组件,并且给它增加了region这个属性

import React, { PureComponent } from 'react'

// 定义一个高阶函数
function enhanceComponent(WrappedComponent) {
  return class NewComponent extends PureComponent {
    render() {
      return <WrappedComponent {...this.props} region="韩国" />
    }
  }
}

class Home extends PureComponent {
  render() {
    return (
      <div>
        <h2>home: {`昵称${this.props.name} 年龄: ${this.props.age} 地区:${this.props.region}`}</h2>
      </div>
    )
  }
}
const EnhanceHome = enhanceComponent(Home)
export default class App extends PureComponent {
  render() {
    return (
      <div>
        App
        <EnhanceHome name="coderwhy" age={18} region='中国'></EnhanceHome>
        <Home name="coderwhy" age={18} region='中国'></Home>
      </div>
    )
  }
}

在这里插入图片描述

3.应用–高阶组件劫持context对象里面的数据,将其增加到相应组件的props里面

import React, { PureComponent, createContext } from 'react'

const userContext = new createContext({
  name: 'coderwhy',
  age: 18,
  region: '中国'
})
// 定义一个高阶函数
function enhanceComponent(WrappedComponent) {
  return class NewComponent extends PureComponent {
    render() {
      return <WrappedComponent {...this.props} region="韩国" />
    }
  }
}
// 因为给每一个组件都增加context属性很麻烦,所以可以使用高阶组件,将他们包裹,增加props
function WithUser(WrappedComponent) {
  return class NewComponent extends PureComponent{
    render() {
      return (
        <userContext.Consumer>
          {
            (user) => {
              return (
                <WrappedComponent {...this.props} {...user}/>
              )
            }
          }
        </userContext.Consumer>
      )
    }
  }
}
// class Home extends PureComponent {
//   render() {
//     return (
//       <userContext.Consumer>
//         {
//           (user) => {
//             return (
//               <div>
//                 <h2>home: {`昵称${user.name} 年龄: ${user.age} 地区:${user.region}`}</h2>
//               </div>
//             )
//           }
//         }
//       </userContext.Consumer>
//     )
//   }
// }
class Home extends PureComponent {
  render() {
    return (
      <div>
        <h2>home: {`昵称${this.props.name} 年龄: ${this.props.age} 地区:${this.props.region}`}</h2>
      </div>
    )
  }
}
// Home.contextType = userContext
class About extends PureComponent {
  render() {
    return (
      <div>
        <h2>about: {`昵称${this.props.name} 年龄: ${this.props.age} 地区:${this.props.region}`}</h2>
      </div>
    )
  }
}
const UserHome = WithUser(Home)
const UserAbout = WithUser(About)
const EnhanceHome = enhanceComponent(Home)
export default class App extends PureComponent {
  render() {
    return (
      <div>
        <h2>App</h2>
        enhanceHome
        <EnhanceHome></EnhanceHome>
        about&&home
        <userContext.Provider value={{ name: 'sasha', age: 18, region: '中国' }}>
          <About></About>
          <UserHome></UserHome>
          <Home></Home>
          <UserAbout></UserAbout>
        </userContext.Provider>
      </div>
    )
  }
}

4.应用–渲染判断鉴权—有点像路由守卫

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cQaT3edQ-1649342396306)(img/渲染判断鉴权.png)]

5.应用–生命周期劫持

利用高阶函数来劫持生命周期,在生命周期中来完成自己的逻辑

import React, { PureComponent } from 'react'
// 高阶组件
function getRenderTime(WrappedComponent) {
  // 这里只能用类组件,因为类组件里面可以使用this
  return class NewComponent extends PureComponent {
    UNSAFE_componentWillMount() {
      this.beginTime = Date.now()
    }
    componentDidMount() {
      this.endTime = Date.now()
      const interval = this.endTime - this.beginTime
      // 可以使用.name属性来获取组件名称
      console.log(WrappedComponent.name,' render时间: ', interval)
    }
    render() {
      return <WrappedComponent></WrappedComponent>
    }
  }
}
// 类组件
class Home extends PureComponent {
  render() {
    return (
      <div>Home</div>
    )
  }
}
// 函数组件
function About() {
  return (
    <div>
      About
    </div>
  )
}
const RenderTimeHome = getRenderTime(Home)
const RenderTimeAbout = getRenderTime(About)
export default class App extends PureComponent {
  render() {
    return (
      <div>
        <RenderTimeHome/>
        <RenderTimeAbout/>
      </div>
    )
  }
}

6.高阶组件的意义

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pk9p8VqJ-1649342396308)(img/高阶函数的意义.png)]

二、组件其他内容补充

1.ref的转发

类组件上使用ref可以获得类组件上的state.props,refs,方法等信息

函数组件上不可以直接使用ref,会报错,需要使用react.forwardRef将这个函数组件包裹起来,这样的话,函数组件就可以有两个参数,第一个为props,接受父组件传过来的数据信息,第二个为ref,接受父组件传过来的ref信息,接受之后可以将它赋值给该函数组件上需要使用的元素,如下about组件里面赋值给了div元素

import React, { PureComponent, createRef, forwardRef } from 'react'

class Home extends PureComponent {
  constructor() {
    super()
    this.state = {
      counter: 0
    }
  }
  render() {
    return (
      <div ref="homediv">
        Home{this.state.counter}
      </div>
    )
  }
}

// function About() {
//   return (
//     <div>
//       about
//     </div>
//   )
// }

// forwardRef已经帮我们封装好了一个高阶组件, 有两个参数,可以帮助我们转发ref
const About = forwardRef(function (props, ref) {
  return (<div ref={ref}> about</div>)
})
export default class App extends PureComponent {
  constructor(props) {
    super(props)
    this.titleRef = createRef()
    this.homeRef = createRef()
    this.aboutRef = createRef()
  }
  render() {
    return (
      <div>
        <h2 ref={this.titleRef}>hello world</h2>
        <Home ref={this.homeRef}></Home>
        {/* 函数组件不可以被赋予ref对象,并且ref不会被认为是props */}
        <About ref={this.aboutRef}></About>
        <button onClick={() => this.printRef()}>打印ref</button>
      </div>
    )
  }
  printRef() {
    console.log(this.titleRef.current);
    console.log(this.homeRef.current);
    console.log(this.aboutRef.current);
  }
}

2.React.Portals的使用

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HyOgsyA5-1649342396309)(img/Portals的使用.png)]

import React, { PureComponent } from 'react'
import ReactDOM from 'react-dom'

class Model extends PureComponent {
  render() {
    // 他的功能是将Model组件渲染到id为model的标签里面
    return ReactDOM.createPortal(this.props.children, document.getElementById('model'))
  }
}

export default class Home extends PureComponent {
  render() {
    return (
      <div>
        <h2>Home</h2>
        <Model>
          <h2>Title</h2>
        </Model>
      </div>
    )
  }
}

3.React.Fragment

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NrZ6IIyJ-1649342396310)(img/fragment的使用.png)]

4.React.StrictMode

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JKf72vMM-1649342396311)(img/严格模式.png)]

三、react中的css

1.react–css中出现的问题

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GzoZwvG5-1649342396312)(img/React中的css.png)]

2.内联样式

import React, { PureComponent } from 'react'

export default class App extends PureComponent {
  constructor() {
    super()
    this.pstyle = {
      color: 'orange',
      fontSize: '20px'
    }
  }
  render() {
    return (
      <div>
        {/* 内联样式必须是驼峰标识 */}
        <h2 style={{ color: 'red', fontSize: '14px' }}>你好 react</h2>
        {/* 可以在状态里面来维护样式 */}
        <p style={this.pstyle}>你是最棒的!</p>
      </div>
    )
  }
}

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ojnABZrw-1649342396312)(img/内联样式.png)]

3.普通的css

很麻烦—会相互层叠

  • 普通的css我们通常会编写到一个单独的文件,之后再进行引入。

  • 这样的编写方式和普通的网页开发中编写方式是一致的:

    • 如果我们按照普通的网页标准去编写,那么也不会有太大的问题;
    • 但是组件化开发中我们总是希望组件是一个独立的模块,即便是样式也只是在自己内部生效,不会相互影响;
    • 但是普通的css都属于全局的css,样式之间会相互影响;
  • 这种编写方式最大的问题是样式之间会相互层叠掉;

4.css modules

1.给style文件命名必须是.module.css等,必须有module

2.引入之后,使用css必须在类名中使用,以{style.className}的方式来书写
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SHWQV3NY-1649342396313)(img/css modules.png)]

import React, { PureComponent } from 'react'
import homeStyle from './style.module.css'
export default class Home extends PureComponent {
  render() {
    return (
      <div className={homeStyle.title}>Home</div>
    )
  }
}

5.css in js

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iti7uL6M-1649342396314)(img/css in js.png)]
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MvJcUUF2-1649342396315)(img/styled-components.png)]

5.1三个特点

import React, { PureComponent } from 'react'
import styled from 'styled-components'

/**
 * 特点:
 * 1.props穿透
 * 2.attrs的使用
 * 3.传入state作为props属性
*/
const IptStyle = styled.input.attrs({
  placeholder: 'Nihaoya',
  // 可以定义变量
  bcolor: 'blue',
})`
  background-color: pink;
  border-color: ${props => props.color}
`

export default class About extends PureComponent {
  constructor() {
    super()
    this.state = {
      color: 'red'
    }
  }
  render() {
    return (
      <div>
        <IptStyle type="text" color={this.state.color} />
        <input type="text"></input>
      </div>
    )
  }
}

5.2可以实现继承

import React, { PureComponent } from 'react'
import Home from '../home/index'
import About from '../about/index'
import appStyle from 'styled-components'
const AppWrapper = appStyle.div`
  font-size: 20px;
  color: pink;
`
const SButton = appStyle.button`
  padding: 10px 20px;
  color: white;
`
// 可以实现继承,padding和color属性继承自SButton
const SPrimaryButton = appStyle(SButton)`
  // padding: 10px 20px;
  // color: red;
  background-color: green;
`
export default class App extends PureComponent {
  render() {
    return (
        <AppWrapper>
          <h2>app</h2>
          <p className='banner'>app</p>
          <Home></Home>
          <About></About>
          <SButton>我是普通的按钮</SButton>
          <SPrimaryButton>我是主要的按钮</SPrimaryButton>
        </AppWrapper>
    )
  }
}

5.3可以定制主题,这样就可以把公共的样式放在theme里面

Sdiv和input有相同的黄色

import React, { PureComponent } from 'react'
import styled, { ThemeProvider }  from 'styled-components'

/**
 * 特点:
 * 1.props穿透
 * 2.attrs的使用
 * 3.传入state作为props属性
*/
const IptStyle = styled.input.attrs({
  placeholder: 'Nihaoya',
  // 可以定义变量
  bcolor: 'blue',
})`
  background-color: pink;
  color:${props => props.theme.themeColor};
  border-color: ${props => props.theme.themeColor};
`
const Sdiv = styled.div`
  color: ${props => props.theme.themeColor}
`
export default class About extends PureComponent {
  constructor() {
    super()
    this.state = {
      color: 'red'
    }
  }
  render() {
    return (
      <ThemeProvider theme={{themeColor: 'yellow'}}>
        <IptStyle type="text" color={this.state.color} />
        <input type="text"></input>
        <Sdiv>
          <h2>about</h2>
        </Sdiv>  
      </ThemeProvider>
    )
  }
}

6.在react中添加class

传入数组也可以
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KYlA75w5-1649342396315)(img/react中添加class.png)]

四、AntDesign组件库的使用

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LMQPYTIB-1649342396316)(img/介绍.png)]
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l1SkQb5u-1649342396317)(img/兼容性.png)]

2.AntD安装

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-maIinAT2-1649342396317)(img/AntDesign的安装.png)]

3.认识craco-- 用来修改webpack中的配置

1.安装craco的库

2.修改package.json里面的js脚本

3.在项目根目录下增加craco.config.js的文件
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S2aTte7e-1649342396318)(img/认识craco.png)]

3.1配置主题

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t9m83bvc-1649342396319)(img/配置主题.png)]

3.2配置别名

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gbLK588D-1649342396319)(img/配置别名.png)]

4.书写案例

见代码,注意comment里面的actions是一个reactDOM数组

五、axios库的使用

1.前端网络请求的几种选择

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ehJ2E2dG-1649342396320)(img/网络请求几种方式.png)]

2.axios的基本使用

index.js文件里面

import App from './axios的使用/App'
// axios的基本配置
import axios from 'axios'
axios.defaults.baseURL = 'https://httpbin.org'
axios.defaults.timeout = 5000
// 设置全局默认的token
axios.defaults.headers.common['token'] = 'sasha'
// 只给post请求配置默认的token
axios.defaults.headers.post['token'] = 'sashapost'

请求拦截器

axios.interceptors.request.use(config => {
  // 1.发送网络请求时, 在界面中间显示loading的组件
  // 2.某一些请求需要用户携带token,如果没有携带,那么直接跳到登录页面
  // params和data序列化的操作
  config.headers.token = 'interceptor'
  return config
}, err => {
  return err
})

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-85jb0gOh-1649342396321)(img/axios的配置信息.png)]

3.axios的二次封装

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7roXeFnQ-1649342396322)(img/axios的二次封装.png)]

六、react过渡动画和纯函数的使用

1.react-transition-group介绍

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-awFARlIl-1649342396322)(img/react-transition-group.png)]

2.主要组件

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uq9fzsza-1649342396323)(img/react-transition-group组件.png)]

2.1、CSSTransition

1.将需要过渡动画的组件或者片段用<CSSTransition></CSSTransition>包裹起来

2.给该标签添加三个属性

  • in:布尔值,用来控制元素隐藏和显示
  • timeout:用来控制过渡时间,单位毫秒,一定主要是number类型的,所以需要用花括号包裹,而不是引号
  • classNames:添加类名,定义相应的样式表
  • appear:布尔值,让其初次渲染的时候也有过渡动画,需要在css中设置相关动画
  • unmountOnExit:布尔值,让隐藏的时候dom元素消失
  • 常见钩子函数,见下面的图
组件
import React, { PureComponent } from 'react'

import { CSSTransition } from 'react-transition-group'
import { Card, Avatar, Button } from 'antd';
import { EditOutlined, EllipsisOutlined, SettingOutlined } from '@ant-design/icons';

// 引入css样式
import './CSSTranistion.css'

const { Meta } = Card;

export default class CSSTransitionDemo extends PureComponent {
  constructor() {
    super()
    this.state = {
      isShow: true
    }
  }
  render() {
    return (
      <div>
        <Button type="primary" onClick={() => this.changeShow()}>显示/隐藏</Button>
        {/* <div style={{display: this.state.isShow? 'block':'none'}}> */}
        <CSSTransition 
          in={this.state.isShow}
          classNames='card'
          timeout={3000}
          unmountOnExit={true}
          appear={true}>
          <Card
            style={{ width: 300 }}
            cover={
              <img
                alt="example"
                src="https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png"
              />
            }
            actions={[
              <SettingOutlined key="setting" />,
              <EditOutlined key="edit" />,
              <EllipsisOutlined key="ellipsis" />,
            ]}
          >
            <Meta
              avatar={<Avatar src="https://joeschmoe.io/api/v1/random" />}
              title="Card title"
              description="This is the description"
            />
          </Card>
        </CSSTransition>
        {/* </div> */}
      </div>
    )
  }
  changeShow() {
    this.setState({
      isShow: !this.state.isShow
    })
  }
}

对应的样式
.card-enter, .card-appear{
  opacity: 0;
  transform: scale(0.6);
}
.card-enter-active, .card-appear-active{
  opacity: 1;
  transform: scale(1);
  transition: all 300ms;
}
/* .card-enter-done{

} */
.card-exit{
  opacity: 1;
  transform: scale(1);
}
.card-exit-active{
  opacity: 0;
  transform: scale(0.6);
  transition: all 300ms;
}
.card-exit-done{
  opacity: 0;
}

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3EF3GWE8-1649342396324)(img/CSSTransition.png)]

2.2、SwitchTransition

在这里插入图片描述

内容切换的时候需要使用的动画

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GyQs0BCg-1649342396324)(img/switchTransition.png)]

组件
import { Button } from 'antd'
import React, { PureComponent } from 'react'
import { SwitchTransition, CSSTransition } from 'react-transition-group'
import './SwitchTransition.css'

export default class SwitchTransitionDemo extends PureComponent {
  constructor() {
    super()
    this.state = {
      isOn: true
    }
  }
  render() {
    const { isOn } = this.state
    return (
      <div>
        <SwitchTransition mode="out-in">
          <CSSTransition
            key={isOn ? 'OFF' : 'ON'}
            classNames='btn'
            timeout={2000}>
            {/* <button
              style={{marginLeft: '200px'}}
              onClick={() => this.setState({ isOn: !isOn })}>
              {isOn ? 'OFF' : 'ON'}
            </button> */}
            <Button
              type="primary"
              style={{marginLeft: '200px', marginTop: '200px'}}
              onClick={() => this.setState({ isOn: !isOn })}>
              {isOn ? 'OFF' : 'ON'}
            </Button>
          </CSSTransition>
        </SwitchTransition>
      </div>
    )
  }
}

css
.btn-enter{
  opacity: 0;
  transform: translateX(-100%);
}
.btn-enter-active{
  opacity: 1;
  transform: translateX(0);
  transition: opacity 2000ms, transform 2000ms;
}

.btn-exit{
  opacity: 1;
  transform: translateX(0);
}
.btn-exit-active{
  opacity: 0;
  transform: translateX(100%);
  transition: opacity 2000ms, transform 2000ms;
}

2.3、TransitionGroup

当我们有一组动画时,需要将这些CSSTransition放入到一个TransitionGroup中来完成动画:

组件
import { Button } from 'antd'
import React, { PureComponent } from 'react'
import { CSSTransition, TransitionGroup } from 'react-transition-group'
import './TransitionGroup.css'
export default class TransitionGroupDemo extends PureComponent {
  constructor(props) {
    super(props)
    this.state = {
      names: ['coderwhy', 'kobe', 'lilei']
    }
  }
  render() {
    return (
      <div style={{ textAlign: 'center' }}>
        <TransitionGroup>
          {
            this.state.names.map((item, index) => {
              return (
                <CSSTransition
                  key={index}
                  timeout={1000}
                  classNames="name"
                  appear={true}>
                  <h2>{item}</h2>
                </CSSTransition>
              )
            })
          }
        </TransitionGroup>
        <Button type="primary" onClick={e => this.addName()}>添加新名字</Button>
      </div>
    )
  }
  addName() {
    const newNames = [...this.state.names]
    newNames.push('lisa')
    this.setState({
      names: newNames
    })
  }
}

css
.name-enter, .name-appear{
  opacity: 0;
  transform: scale(0.6);
}
.name-enter-active, .name-appear-active{
  opacity: 1;
  transform: scale(1);
  transition: all 1000ms;
}
.name-enter-done{
  color: pink;
}
.name-exit{
  opacity: 1;
  transform: scale(1);
}
.name-exit-active{
  opacity: 0;
  transform: scale(.6);
  transition: all 1000ms;
}
.name-exit-done{
  opacity: 0;
}

3.javascript纯函数

3.1含义

在这里插入图片描述

产生副作用的意思是修改了外部传过来的对象的值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WMUp7WyX-1649342396325)(img/纯函数.png)]

3.2纯函数分析

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7v85mgTJ-1649342396326)(img/纯函数分析.png)]

七、redux的使用

1.为什么需要redux

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h8Dfcvo2-1649342396327)(img/为什么需要redux.png)]

2.核心理念

2.1.store&action

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RxoxB0qq-1649342396327)(img/redux核心理念.png)]

2.2.reducer(类似vue的mutations)

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9EU0yx7J-1649342396328)(img/reducer.png)]

3.Redux的三大原则

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fNXX2j2u-1649342396329)(img/redux的三大原则.png)]

4.Redux测试项目搭建

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tvLSEgvg-1649342396329)(img/redux测试项目搭建.png)]

5.redux使用流程

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DZnAZ8tg-1649342396330)(img/Redux的使用流程.png)]

6.redux融入react

6.1自定义connect高阶函数–返回一个高阶组件

import { PureComponent } from 'react'
// import store from '../store/index'
import { StoreContext } from './context'

export function connect(mapStateToProps, mapDispatchToProp) {
  return function enhanceHOC(WrappedComponent) {
    class NewEnhanceComponent extends PureComponent {
      constructor(props, context) {
        super(props)
        this.state = {
          storeState: mapStateToProps(context.getState())
        }
      }
      // 订阅监听
      componentDidMount() {
        this.unsubscribe = this.context.subscribe(() => {
          this.setState({
            storeState: mapStateToProps(this.context.getState())
          })
        })
      }
      // 取消订阅
      componentWillUnmount() {
        this.unsubscribe()
      }
      render() {
        return <WrappedComponent
          {...mapStateToProps(this.context.getState())}
          {...mapDispatchToProp(this.context.dispatch)}
          {...this.props} />
      }
    }
    NewEnhanceComponent.contextType = StoreContext
    return NewEnhanceComponent
  }
}

// 返回一个高阶组件
在组件中使用connect函数–返回一个高阶组件,将组件的方法和状态都变成属性来使用
import React from 'react'
import { connect } from '../utills/connect.js'
import { subAction } from '../store/actionCreators'
function Home(props) {
  return (
    <div>
      <h2>home</h2>
      <h2>当前计数: {props.counter}</h2>
      <button onClick={() => props.decrement()}>-1</button>
      <button onClick={() => props.subNumber(5)}>-5</button>
    </div>
  )
}

const mapStateToProps = (state) => {
  return {
    counter: state.counter
  }
};
const mapDispatchToProps = (dispatch) => {
  return {
    decrement: function() {
      return dispatch(subAction(1))
    },
    subNumber: function(num) {
      return dispatch(subAction(num))
    }
  }
};

export default connect(mapStateToProps, mapDispatchToProps)(Home)

6.2自定义context函数–目的是把connect中对store的依赖分离出来

import React from 'react'
export const StoreContext = React.createContext()

6.3context处理store

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nbumpRoX-1649342396330)(img/context处理store.png)]

import React from 'react';
import ReactDOM from 'react-dom';

import App from './04.redux的使用/App.js'
import store from './04.redux的使用/store/index'
import { StoreContext } from './04.redux的使用/utills/context'
// value值是必须的
ReactDOM.render(
  // <React.StrictMode>
  <StoreContext.Provider value={store}>
      <App />
  </StoreContext.Provider>,
  // </React.StrictMode>,
  document.getElementById('root')
);

八.组件中的异步操作—访问后台数据的时候,需要在组件生命周期函数中发起异步请求

import React, { PureComponent } from 'react'
// import { connect } from '../utills/connect.js'
import { connect } from 'react-redux'
import { subAction,changeBanners, changeRecommends } from '../store/actionCreators'

import axios from 'axios'
class Home extends PureComponent {
    // 发起异步请求
  componentDidMount() {
    axios({
      url: 'http://123.207.32.32:8000/home/multidata',
      method: 'get'
    }).then(res => {
      const data = res.data.data
      this.props.changeBanners(data.banner.list)
      this.props.changeRecommends(data.recommend.list)
    })
  }
  render() {
    return (
      <div>
        <h2>home</h2>
        <h2>当前计数: {this.props.counter}</h2>
        <button onClick={() => this.props.decrement()}>-1</button>
        <button onClick={() => this.props.subNumber(5)}>-5</button>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    counter: state.counter
  }
};
const mapDispatchToProps = (dispatch) => {
  return {
    decrement: function() {
      return dispatch(subAction(1))
    },
    subNumber: function(num) {
      return dispatch(subAction(num))
    },
    changeBanners(banners) {
      dispatch(changeBanners(banners))
    },
    changeRecommends(recommends) {
      dispatch(changeRecommends(recommends))
    }
  }
};

export default connect(mapStateToProps, mapDispatchToProps)(Home)

用来访问后台数据,coderwhy老师的服务器http://123.207.32.32:8000/home/multidata
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zamgdynv-1649342396331)(img/redux中的异步操作.png)]

1.redux中的异步操作–redux-thunk的使用

需要使用中间件来操作,官方推荐redux-chunk

它的主要作用是将dispatch(action)中的action可以是一个函数来使用,因为我们之前的action默认是一个js对象

store/actionCreate.js

import { ADD_NUMBER, SUB_NUMBER, CHANGE_BANNER, CHANGE_RECOMMEND, FETCH_HOME_MULTIDATA } from "./constants.js"
import axios from 'axios'
export const addAction = function (num) {
  return {
    type: ADD_NUMBER,
    num: num
  }
}
export const subAction = function (num) {
  return {
    type: SUB_NUMBER,
    num: num
  }
}
// 轮播图和推荐的action
export const changeBanners = (banners) => {
  return {
    type: CHANGE_BANNER,
    banners: banners
  }
}
export const changeRecommends = (recommends) => {
  return {
    type: CHANGE_RECOMMEND,
    recommends: recommends
  }
}

// redux-thunk中的函数
export const getHomeMultidata = (dispatch) => {
  // console.log('redux-thunk');
  axios({
    url: 'http://123.207.32.32:8000/home/multidata',
    method: 'get'
  }).then(res => {
    const data = res.data.data
    dispatch(changeBanners(data.banner.list))
    dispatch(changeRecommends(data.recommend.list))
  })
}

// redux-saga拦截的action
export const fetchHomeMultidataAction = {
  type: FETCH_HOME_MULTIDATA
}

组件中的使用,其实还是在生命周期函数中调用

import React, { PureComponent } from 'react'
// import { connect } from '../utills/connect.js'
import { connect } from 'react-redux'
import { subAction,changeBanners, changeRecommends, getHomeMultidata } from '../store/actionCreators'

// import axios from 'axios'
class Home extends PureComponent {
  componentDidMount() {
    // axios({
    //   url: 'http://123.207.32.32:8000/home/multidata',
    //   method: 'get'
    // }).then(res => {
    //   const data = res.data.data
    //   this.props.changeBanners(data.banner.list)
    //   this.props.changeRecommends(data.recommend.list)
    // })
    this.props.getHomeMultidata()
  }
  render() {
    return (
      <div>
        <h2>home</h2>
        <h2>当前计数: {this.props.counter}</h2>
        <button onClick={() => this.props.decrement()}>-1</button>
        <button onClick={() => this.props.subNumber(5)}>-5</button>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    counter: state.counter
  }
};
const mapDispatchToProps = (dispatch) => {
  return {
    decrement: function() {
      return dispatch(subAction(1))
    },
    subNumber: function(num) {
      return dispatch(subAction(num))
    },
    changeBanners(banners) {
      dispatch(changeBanners(banners))
    },
    changeRecommends(recommends) {
      dispatch(changeRecommends(recommends))
    },
    getHomeMultidata() {
      dispatch(getHomeMultidata)
    }
  }
};

export default connect(mapStateToProps, mapDispatchToProps)(Home)

在这里插入图片描述

2.redux-devtools

1.浏览器下载edux-devtools插件

2.项目store/index.js配置中间件

import * as redux from 'redux'
import reducer from './reducer.js'

// 1.引入saga库
import createSagaMiddleware from 'redux-saga'
// 2.创建saga中间件
const sagaMiddleware = createSagaMiddleware()

// 3.应用一些中间件
// redux.applyMiddleware(中间件1, 中间件2, 中间件3)
const storeenhancer = redux.applyMiddleware(sagaMiddleware)
// composeEnhancer函数,使用redux-devtools
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || redux.compose;
const store = redux.createStore(reducer, composeEnhancers(storeenhancer))

// 4.开启saga中间件
sagaMiddleware.run(saga)

export default store

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DR53u7aS-1649342396333)(img/redux-devtools.png)]

3.generator

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vUHqSRkN-1649342396333)(img/es6-generator.png)]

4.redux-saga的使用

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8JXT9wF5-1649342396334)(img/redux-saga的使用.png)]

4.1配置redux-saga库

store/index.js

import * as redux from 'redux'
import reducer from './reducer.js'
import saga from './saga'

// 1.引入saga库
import createSagaMiddleware from 'redux-saga'
// 2.创建saga中间件
const sagaMiddleware = createSagaMiddleware()

// 3.应用一些中间件
// redux.applyMiddleware(中间件1, 中间件2, 中间件3)
const storeenhancer = redux.applyMiddleware(sagaMiddleware)
// composeEnhancer函数,使用redux-devtools
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || redux.compose;
const store = redux.createStore(reducer, composeEnhancers(storeenhancer))

// 4.开启saga中间件
sagaMiddleware.run(saga)

export default store

4.2定义actionCreate对象

// redux-saga拦截的action
export const fetchHomeMultidataAction = {
  type: FETCH_HOME_MULTIDATA
}

4.3定义saga函数

store/saga.js

import axios from 'axios'
import { FETCH_HOME_MULTIDATA } from './constants'
import { takeEvery, put, all } from 'redux-saga/effects'
import { changeBanners, changeRecommends } from './actionCreators'

function* fetchHomeMultidata(action) {
  const res = yield axios.get('http://123.207.32.32:8000/home/multidata')
  // // console.log(res);
  // yield put(changeBanners(res.data.data.banner.list))
  // yield put(changeRecommends(res.data.data.recommend.list))
  // 以下也可以,和上面一样的作用
  yield all([
    yield put(changeBanners(res.data.data.banner.list)),
    yield put(changeRecommends(res.data.data.recommend.list))
  ])
}

// 拦截每一个类型为FETCH_HOME_MULTIDATA的action,  并且执行fetchHomeMultidata这个生成器函数
function* mySaga() {
  // takeEvery(执行每一个)   takeLastest(只会执行最后一个)
  yield takeEvery(FETCH_HOME_MULTIDATA, fetchHomeMultidata)
}

// export default 生成器函数
export default mySaga

5.中间件的实现方式—后面看,没有时间了

coderwhy-react-17节:01:20:30暂停

6.reducer代码拆分

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3r2Bszql-1649342396335)(img/reducer代码拆分.png)]
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UstLKIPI-1649342396335)(img/combineReducer函数.png)]

九、状态管理方案

方案

1.组件内部自己维护state

2.redux

3.cintext上下文共享

推荐

  • ui相关的组件内部可以维护的状态,在组件自己的内部使用

  • 只要是需要共享的状态,都交给redux来处理’

  • 服务器请求过来的数据,交给redux处理

后续会补充的东西–项目中补充

redux和immutableJS结合使用

一些性能更新
``

4.3定义saga函数

store/saga.js

import axios from 'axios'
import { FETCH_HOME_MULTIDATA } from './constants'
import { takeEvery, put, all } from 'redux-saga/effects'
import { changeBanners, changeRecommends } from './actionCreators'

function* fetchHomeMultidata(action) {
  const res = yield axios.get('http://123.207.32.32:8000/home/multidata')
  // // console.log(res);
  // yield put(changeBanners(res.data.data.banner.list))
  // yield put(changeRecommends(res.data.data.recommend.list))
  // 以下也可以,和上面一样的作用
  yield all([
    yield put(changeBanners(res.data.data.banner.list)),
    yield put(changeRecommends(res.data.data.recommend.list))
  ])
}

// 拦截每一个类型为FETCH_HOME_MULTIDATA的action,  并且执行fetchHomeMultidata这个生成器函数
function* mySaga() {
  // takeEvery(执行每一个)   takeLastest(只会执行最后一个)
  yield takeEvery(FETCH_HOME_MULTIDATA, fetchHomeMultidata)
}

// export default 生成器函数
export default mySaga

5.中间件的实现方式—后面看,没有时间了

coderwhy-react-17节:01:20:30暂停

6.reducer代码拆分

在这里插入图片描述

[外链图片转存中…(img-3r2Bszql-1649342396335)]
在这里插入图片描述

[外链图片转存中…(img-UstLKIPI-1649342396335)]

九、状态管理方案

方案

1.组件内部自己维护state

2.redux

3.cintext上下文共享

推荐

  • ui相关的组件内部可以维护的状态,在组件自己的内部使用

  • 只要是需要共享的状态,都交给redux来处理’

  • 服务器请求过来的数据,交给redux处理

后续会补充的东西–项目中补充

redux和immutableJS结合使用

一些性能更新

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值