Redux 是什么

Redux is a predictable state container for JavaScript apps

Redux概念

store: 应用数据的存储中心
action: 应用数据的改变的描述
reducer: 决定应用数据新状态的函数,接收应用之前的状态和一个 action 返回数据的新状态。
state: 状态
middleware: redux 提供中间件的方式,完成一些 流程的自定义控制,同时形成其插件体系。

流程

image.png

环境准备

npx create-react-app cra
cd cra 
npm start

在 cra项目中安装redux

yarn add redux

redux整体感知

// reducer
const weight = (state = 160, action) => {
    switch (action.type) {
        case 'eat':
            return state + 10
        case 'hungry':
            return state - 10
        default:
            return 160
    }
}

const store = createStore(weight)

console.log(store.getState())

store.dispatch({ type: 'eat' })
console.log('我吃了一些事物')
console.log(store.getState())

console.log('我饿了好几天')
store.dispatch({ type: 'hungry' })
console.log(store.getState())
console.log('我又饿了好几天')
store.dispatch({ type: 'hungry' })
console.log(store.getState())

reducer 里面使用switch语句根据传入的类型,输出新的状态
把reducer 传入 createStore(weight)
通过 dispatch 传入不同的类型,改变状态state。
store.dispatch({ type: 'hungry' })
通过 store.getState() 获取当前的状态

通过subscribe订阅,实现redux数据响应

const store = createStore(weight)


const watch = () => {
    const cur = store.getState()
    console.log(`stark wang 现在体重为${cur}斤`)
}

store.subscribe(watch)
// watch()


store.dispatch({type:'eat'})

store.dispatch({type:'eat'})

store.dispatch({type:'eat'})

store.dispatch({ type: 'hungry' })

redux和react的使用
stark.redux.js

import { createStore } from 'redux'

const EAT = 'eat'
const HUNGRY = 'hungry'

// reducer
export const weight = (state = 160 , action) => {
  switch (action.type) {
    case EAT:
      return state + 10
    case HUNGRY:
      return state - 10
    default:
      return 160
  }
}


// action
export const eat = () => {
  console.log('stark wang 正在吃山珍海味')
  return {type: EAT}
}

export const hungry = () => {
  console.log('饿了一天')
  return {type: HUNGRY}
}

App.js

import React from 'react'
import logo from './logo.svg'
import './App.css'
import { eat, hungry } from './stark.redux'

class App extends React.Component {
  render () {
    const store = this.props.store
    const num = store.getState()
    return (
      <div className='App'>
        <header className='App-header'>
          <img src={logo} className='App-logo' alt='logo' />
          <p>
            【redux完全指南】系列1:从入门到会用
            <br></br>
            hi gusy, I am stark
          </p>
          <a
            className='App-link'
            href='https://shudong.wang'
            target='_blank'
            rel='noopener noreferrer'>跟着stark wang 学redux</a>
          <h2>stark wang 当前的体重为{num}斤</h2>
          <button onClick={() => {store.dispatch(eat())}}>
            吃了一坨山珍海味
          </button>
          <button onClick={() => {store.dispatch(hungry())}}>
            饿了一天
          </button>
        </header>
      </div>
    )
  }

}

export default App

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { createStore } from 'redux'
import { weight } from './stark.redux'

const store = createStore(weight)

const render = () =>{
    ReactDOM.render(<App store={store} />, document.getElementById('root'));
}
render()

store.subscribe(render)

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

使用connect让react和redux更优雅的结合

import React from 'react'
import logo from './logo.svg'
import './App.css'
import { eat, hungry } from './stark.redux'
import { connect } from 'react-redux'
class App extends React.Component {
  render () {
    const {num, eat, hungry} = this.props
    return (
      <div className='App'>
        <header className='App-header'>
          <img src={logo} className='App-logo' alt='logo' />
          <p>
            【redux完全指南】系列1:从入门到会用
            <br></br>
            hi gusy, I am stark
          </p>
          <a
            className='App-link'
            href='https://shudong.wang'
            target='_blank'
            rel='noopener noreferrer'>跟着stark wang 学redux</a>
          <h2>stark wang 当前的体重为{num}斤</h2>
          <button onClick={() => {eat()}}>
            吃了一坨山珍海味
          </button>
          <button onClick={() => {hungry()}}>
            饿了一天
          </button>
        </header>
      </div>
    )
  }

}

// 把state挂在到 props 上面
// const mapStateToProps = (state)=>{
//   return {num:state}
// }

// 把action 挂在到 props上面
// const actionCreators = {eat,hungry}
export default connect((state)=>{
  return {num:state}
},{eat,hungry})(App)
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { createStore } from 'redux'
import { weight } from './stark.redux'
import { Provider } from 'react-redux'

const store = createStore(weight)

// const render = () =>{
ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
);
// }
// render()

// store.subscribe(render)

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

使用react-thunk解决异步action问题

image.png
使用方式

import { createStore, applyMiddleware } from 'redux'

import thunk from 'redux-thunk'

const store = createStore(weight, applyMiddleware(thunk))
export const eatAsync = () =>{
  return dispatch =>{
    setTimeout(()=>{
      // dispatch(eat('煎饼')) 
      dispatch({type: EAT}) 
    },2000)
  }
}

源码

import { createStore } from 'redux'

const EAT = 'eat'
const HUNGRY = 'hungry'

// reducer
export const weight = (state = 160 , action) => {
  switch (action.type) {
    case EAT:
      return state + 10
    case HUNGRY:
      return state - 10
    default:
      return 160
  }
}

// const store = createStore(weight)

// action
export const eat = (data) => {
  console.log('stark wang 正在吃'+ data)
  return {type: EAT}
}

export const hungry = () => {
  console.log('饿了一天')
  return {type: HUNGRY}
}

export const eatAsync = () =>{
  return dispatch =>{
    setTimeout(()=>{
      dispatch(eat('煎饼')) 
    },2000)
  }
}
import React from 'react'
import logo from './logo.svg'
import './App.css'
import { eat, hungry, eatAsync } from './stark.redux'
import { connect } from 'react-redux'
class App extends React.Component {
  render () {
    const {num, eat, hungry , eatAsync} = this.props
    return (
      <div className='App'>
        <header className='App-header'>
          <img src={logo} className='App-logo' alt='logo' />
          <p>
            【redux完全指南】系列1:从入门到会用
            <br></br>
            hi gusy, I am stark
          </p>
          <a
            className='App-link'
            href='https://shudong.wang'
            target='_blank'
            rel='noopener noreferrer'>跟着stark wang 学redux</a>
          <h2>stark wang 当前的体重为{num}斤</h2>
          <button onClick={() => {eat()}}>
            吃了一坨山珍海味
          </button>
          <button onClick={() => {eatAsync()}}>
            等了一会,吃了一个煎饼
          </button>
          <button onClick={() => {hungry()}}>
            饿了一天
          </button>
        </header>
      </div>
    )
  }

}
// const mapStateToProps = (state)=>{
//   return {num:state}
// }

// const actionCreators = {eat,hungry}
export default connect((state)=>{
  return {num:state}
},{eat,hungry,eatAsync})(App)
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { createStore, applyMiddleware } from 'redux'
import { weight } from './stark.redux'
import { Provider } from 'react-redux'

import thunk from 'redux-thunk'

const store = createStore(weight, applyMiddleware(thunk))

// const render = () =>{
ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
);
// }
// render()

// store.subscribe(render)

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

使用axios请求真实的api

export const getArticle = () =>{
  return dispatch =>{
    setTimeout(()=>{
      // dispatch(eat('煎饼')) 
      dispatch(()=>{
        axios.get('/v1/article/list').then(res=>{
          console.log('article',res)
        })
      }) 
    },2000)
  }
}

解决跨域问题

1.
npm run eject

2.
在package.json 文件末尾添加  "proxy": "http://api.shudong.wang"

3. 
 axios.get('/v1/article/list').then(res=>{
          console.log('article',res)
        })

把请求api数据渲染到页面上面

拆分state把请求api文章列表,数据渲染到页面上

const initState = {
  num: 160,
  list: []
}

// reducer
export const weight = (state = initState , action) => {
  switch (action.type) {
    case EAT:
    return {...state, num: state.num + 10}
    case HUNGRY:
    return {...state, num: state.num - 10}
    case ARTICLE_LIST:
    console.log('action',action)
      return {...state, list: action.playload.article}
    default:
      return initState
  }
}
export const getArticle = () =>{
  return dispatch =>{
    setTimeout(()=>{
      // dispatch(eat('煎饼')) 
        axios.get('/v1/article/list').then(res=>{
          console.log('article',res)
          //做了一个分发
          dispatch({type:ARTICLE_LIST,playload:res.data})
        })
    },2000)
  }
}

页面渲染

    const {num, eat, hungry , eatAsync, getArticle, list} = this.props

render
          {list.map((item,index)=>{
            return <div key={index}>
              {item.title}
            </div>
          })}
          
export default connect((state)=>{
  return {num: state.num,list:state.list}
},{eat,hungry,eatAsync,getArticle})(App)

装饰器模式

babel

npm i @babel/plugin-proposal-decorators -S

  "babel": {
    "presets": [
      "react-app"
    ],
    "plugins":[
      [
        "@babel/plugin-proposal-decorators",
        {
          "legacy": true
        }
      
      ]
    ]
  },

语法糖{把state 和 action 挂在到 当前的组件props上}
第一个参数是 state 第二个参数是action

// const actionCreators = {eat,hungry}
// export default connect((state)=>{
//   return {num: state.num,list:state.list}
// },{eat,hungry,eatAsync,getArticle})(App)
@connect(state => state, { eat, hungry, eatAsync, getArticle })

神仙姥姥敲bug
18 声望2 粉丝

引用和评论

0 条评论