入门 Redux

Redux is a predictable state container for JavaScript apps.
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。

这是 redux 官网的原话

在这里插入图片描述
我最早接触的框架是 Vue,这个图我自己觉得和 vuex 好像有一些相似的地方。

我们今天就写一个TODOList 的小 demo ,来入门学习一下 redux
(为了效果好看,使用 antd-ui 组件库)


1. 初始化项目

安装官方脚手架之后

mkdir ReduxDemo
cd ReduxDemo
create-react-app demo
cd demo
npm start

对的,就是这么简单

不出意外,就能看到平常你看见的样子了。

项目精简

src 目录下只留下一个 index.js,新建一个 TodoList.js

import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList'

ReactDOM.render(
  <TodoList />,
  document.getElementById('root')
);

TodoList.js

import React, { Component } from 'react';
class TodoList extends Component {
  render() {
    return (
      <div>Hello World</div>
    );
  }
}
export default TodoList;
安装UI组件库

(不想安装也行,就是样子很不好看,功能没有多大影响)
官网地址 https://ant.design/docs/react/use-with-create-react-app-cn

npm install antd --save

2. 编写基本界面

TodoList.js 引入

import React, { Component } from 'react';
import 'antd/dist/antd.css'
import { Input } from 'antd'

class TodoList extends Component {
  render() {
    return (
      <div>
        <div>
          <Input placeholder='请输入' style={{ width: '250px' }} />
        </div>
      </div>
    );
  }
}
export default TodoList;

不出意外,你得页面上面,会出现一个 input 输入框

增加按钮

import React, { Component } from 'react';
import 'antd/dist/antd.css'
import { Input, Button } from 'antd'

class TodoList extends Component {
  render() {
    return (
      <div style={{margin:'10px'}}>
        <div>
          <Input placeholder='请输入' style={{ width: '250px' }} />
          <Button type="primary">添加</Button>
        </div>
      </div>
    );
  }
}
export default TodoList;

一个按钮就可以了。接下来是 List 列表(先使用假数据)

在 class 外面声明一个 list 数组

const data=[
    'react',
    'vue',
    'ang'
]

增加 List 组件

import { Input, Button, List } from 'antd'
<div style={{ margin: '10px' }}>
  <div>
    <Input placeholder='请输入' style={{ width: '300px' }} />
    <Button type="primary">添加</Button>
  </div>
  <div style={{ width: '300px' }}>
    <List
      bordered
      dataSource={data}
      renderItem={item => (<List.Item>{item}</List.Item>)}
    />
  </div>
</div>

在这里插入图片描述
对的,不出意外,你的页面应该是长这个样子的

3. 正式进入 redux,创建 store 和 reducer

Redux工作流程中有四个部分,最重要的就是store这个部分,因为它把所有的数据都放到了store中进行管理。在编写代码的时候,因为重要,所以要优先编写store。

想使用,先安装

npm install --save redux

在 src 目录下,创建 store 文件夹。文件夹下创建一个index.js文件。index.js就是整个项目的store文件

index.js

import { createStore } from 'redux'
const store = createStore()
export default store

从 redux 中导出 createStore ,使用 createStore方法创建一个 store仓库,之后进行导出

这个仓库创建好了,需要一位管理员来管理这个仓库,Reducers 就是这么一位天选之子。同级目录下创建 reducer.js 文件

reducer.js

const defaultState = {}
export default (state = defaultState, action) => {
  return state
}

这位管理员有一个本子 state,里面记载着仓库的一切。同时我们给这个本子添加一个初始的内容 defaultState,返回这个本子上面的内容

把reducer引入到store中,再创建store时,以参数的形式传递给store。

import { createStore } from 'redux'
import reducer from './reducer'
const store = createStore(reducer)
export default store
转移数据

把刚刚在页面中定义的 list 数组迁移到 reducer 中,给这个记录着仓库一切的本子赋上初始值

const defaultState = {
  inputValue: '请输入',
  list: [
    'react',
    'vue',
    'ang'
  ]
}
export default (state = defaultState, action) => {
  return state
}
获取数据

仓库里有东西,就可以获取了。

todoList 组件要使用 store,就在 src/TodoList.js 文件夹中,进行引入。在 constructor 中打印 store 里面的数据

constructor(props) {
    super(props);
    console.log(store.getState())
  }

在这里插入图片描述
控制台已经打印出我们需要的数据,接下来我们进行赋值

import React, { Component } from 'react';
import 'antd/dist/antd.css'
import { Input, Button, List } from 'antd'
import store from './store/index'

class TodoList extends Component {

  constructor(props) {
    super(props);
    console.log(store.getState())
    this.state = store.getState()
  }
  

  render() {
    return (
      <div style={{ margin: '10px' }}>
        <div>
          <Input
            placeholder={this.state.inputValue} 
            style={{ width: '300px' }}
          />
          <Button type="primary">添加</Button>
        </div>
        <div style={{ width: '300px' }}>
          <List
            bordered
            dataSource={this.state.list}
            renderItem={item => (<List.Item>{item}</List.Item>)}
          />
        </div>
      </div>
    );
  }
}
export default TodoList;

4. TodoList 的变化引起 redux 变化

我们给输入框增加一个 onChange 事件

<Input
  placeholder={this.state.inputValue}
  onChange={this.changeInputValue}
  style={{ width: '300px' }}
/>

定义这个事件,同时在 constructor 中进行this的绑定,修改this的指向。

constructor(props) {
  super(props);
  this.state = store.getState()
  this.changeInputValue = this.changeInputValue.bind(this)
}
...

changeInputValue(e) {
  console.log(e.target.value)
}

在输入框中,输入文字,可以看到控制台输出的相应的文字。好的,这就成功了。

创建 Action

想改变 Redux 里边 State 的值就要创建 Action 了。Action 就是一个对象,这个对象一般有两个属性,第一个是对 Action 的描述,第二个是要改变的值。

changeInputValue(e) {
  const action = {
    type: 'change_input_value',
    value: e.target.value
  }
}
派发 dispatch

action就创建好了,通过dispatch()方法传递给store

changeInputValue(e) {
  const action = {
    type: 'change_input_value',
    value: e.target.value
  }
  store.dispatch(action)
}

(这就相当于我要做一件事,做什么事呢?我想告诉仓库我想改变 input 输入框里面的值,然后我把值传递给你,怎么弄那是你的事,之后通过 dispatch 把这件事告诉仓库)
😌😌😌😌

store 的处理

store 只是一个仓库,它并没有管理能力,它会把接收到的 action 自动转发给 Reducer。

在 reducer.js 里面,打印出这两个值
在这里插入图片描述

Reducer 已经拿到了原来的数据和新传递过来的数据,现在要作的就是改变store里的值。我们先判断type是不是正确的,如果正确,我们需要从新声明一个变量newState。(记住:Reducer里只能接收state,不能改变state。), 所以我们声明了一个新变量,然后再次用return返回回去。

const defaultState = {
  inputValue: '请输入',
  list: [
    'react',
    'vue',
    'ang'
  ]
}
export default (state = defaultState, action) => {
  if (action.type === 'changeInput') {
    let newState = JSON.parse(JSON.stringify(state))
    newState.inputValue = action.value
    return newState
  }
  return state
}

(当reducer 知道你改变 input 输入框的值,当判断类型正确的时候,它会先拷贝出一份,然后把你传递给它的值赋值给仓库里面的值, 同时返回)

组件更新

TodoList.js

constructor(props) {
  super(props);
  this.state = store.getState()
  this.changeInputValue = this.changeInputValue.bind(this)
  this.storeChange = this.storeChange.bind(this)
  //订阅Redux的状态
  store.subscribe(this.storeChange)
}
storeChange() {
  this.setState(store.getState())
}

给 button 添加事件

<Button type="primary" onClick={this.clickBtn}>添加</Button>
clickBtn() {
  const action = {
    type: 'addItem'
  }
  store.dispatch(action)
}
if (action.type === 'addItem') {
  let newState = JSON.parse(JSON.stringify(state))
  newState.list.push(newState.inputValue)
  newState.inputValue = ''
  return newState
}

不出意外的话,当你输入文字,点击添加的时候,下面的 list 就会出现相应的文字

删除 TodoList-item

给每一个 ListItem 添加一个 deleteItem 事件

<List
  bordered
  dataSource={this.state.list}
  renderItem={(item, index) => (
    <List.Item onClick={this.deleteItem.bind(this, index)}>
      {item}
    </List.Item>
    )
  }
/>
deleteItem(index) {
  console.log(index)
  const action = {
    type: 'deleteItem',
    index
  }
  store.dispatch(action)
}

点击出现相对应的序号,就是成功了。

if (action.type === 'deleteItem') {
  let newState = JSON.parse(JSON.stringify(state))
  newState.list.splice(action.index,1)
  return newState
}

点击各项,成功删除

来到这一步,我们就成功实现了。完美撒花 🎉🎉🎉🎉🎉🎉

5.代码优化

写 Redux Action 的时候,我们写了很多 Action 的派发,产生了很多 Action Types,如果需要Action的地方我们就自己命名一个Type,会出现两个基本问题:

  • 这些 Types 如果不统一管理,不利于大型项目的服用,设置会长生冗余代码。
  • 因为 Action 里的 Type,一定要和 Reducer 里的 type一一对应在,所以这部分代码或字母写错后,浏览器里并没有明确的报错,这给调试带来了极大的困难。

store 文件夹下,新建一个 actionTypes.js

export const  CHANGE_INPUT = 'changeInput'
export const  ADD_ITEM = 'addItem'
export const  DELETE_ITEM = 'deleteItem'

TodoList.js

//..
import {
  CHANGE_INPUT,
  ADD_ITEM,
  DELETE_ITEM,
} from './store/actionTypes'

class TodoList extends Component {

  constructor(props) {
    // ...
  }
  render() {
    //....
  }
  storeChange() {
    this.setState(store.getState())
  }

  changeInputValue(e) {
    const action = {
      type: CHANGE_INPUT,
      value: e.target.value
    }
    store.dispatch(action)
  }
  clickBtn() {
    const action = {
      type: ADD_ITEM
    }
    store.dispatch(action)
  }
  deleteItem(index) {
    console.log(index)
    const action = {
      type: DELETE_ITEM,
      index
    }
    store.dispatch(action)
  }
}
export default TodoList;

reducer.js

import {
  CHANGE_INPUT,
  ADD_ITEM,
  DELETE_ITEM
} from './actionTypes'

const defaultState = {
  inputValue: '请输入',
  list: [
    'react',
    'vue',
    'ang'
  ]
}
export default (state = defaultState, action) => {
  if (action.type === CHANGE_INPUT) {
    let newState = JSON.parse(JSON.stringify(state))
    newState.inputValue = action.value
    return newState
  }

  if (action.type === ADD_ITEM) {
    let newState = JSON.parse(JSON.stringify(state))
    newState.list.push(newState.inputValue)
    newState.inputValue = ''
    return newState
  }

  if (action.type === DELETE_ITEM) {
    let newState = JSON.parse(JSON.stringify(state))
    newState.list.splice(action.index,1)
    return newState
  }
  return state
}
把所有的Redux Action放到一个文件里进行管理。

在 store 文件夹下面,建立 actionCreators.js

import {
  CHANGE_INPUT,
  ADD_ITEM,
  DELETE_ITEM
} from './actionTypes'

export default changeInputAction = (value) => {
  type: CHANGE_INPUT,
  value
}

TodoList.js

import {
  changeInputAction
} from './store/actionCreators'
changeInputValue(e) {
  const action = changeInputAction(e.target.value)
  store.dispatch(action)
}

改造剩下的两个

import {
  CHANGE_INPUT, 
  ADD_ITEM,
  DELETE_ITEM
}  from './actionTypes'

export const changeInputAction = (value)=>({
    type:CHANGE_INPUT,
    value
})

export const addItemAction = ()=>({
    type:ADD_ITEM
})

export const deleteItemAction = (index)=>({
    type:DELETE_ITEM,
    index
})
import React, { Component } from 'react';
import 'antd/dist/antd.css'
import { Input, Button, List } from 'antd'
import store from './store/index'

import {
  changeInputAction,
  addItemAction,
  deleteItemAction
} from './store/actionCreators'

class TodoList extends Component {

  constructor(props) {
    super(props);
    this.state = store.getState()
    this.changeInputValue = this.changeInputValue.bind(this)
    this.storeChange = this.storeChange.bind(this)
    store.subscribe(this.storeChange)
  }

  render() {
    return (
      <div style={{ margin: '10px' }}>
        <div>
          <Input
            placeholder={this.state.inputValue}
            onChange={this.changeInputValue}
            value={this.inputValue}
            style={{ width: '300px' }}
          />
          <Button type="primary" onClick={this.clickBtn}>添加</Button>
        </div>
        <div style={{ width: '300px' }}>
          <List
            bordered
            dataSource={this.state.list}
            renderItem={(item, index) => (
              <List.Item onClick={this.deleteItem.bind(this, index)}>
                {item}
              </List.Item>
            )
            }
          />
        </div>
      </div>
    );
  }

  storeChange() {
    this.setState(store.getState())
  }

  changeInputValue(e) {
    const action = changeInputAction(e.target.value)
    store.dispatch(action)
  }
  clickBtn() {
    const action = addItemAction()
    store.dispatch(action)
  }
  deleteItem(index) {
    const action = deleteItemAction(index)
    store.dispatch(action)
  }
}
export default TodoList;

改造到这里代码依然正常运行。此时我们可以进一步改造,将 UI部分与逻辑部分开

src 目录下新建 TodoListUI.js

import React, { Component } from 'react';
import 'antd/dist/antd.css'
import { Input, Button, List } from 'antd'

class TodoListUI extends Component {

  render() {
    return (
      <div style={{ margin: '10px' }}>
        <div>
          <Input
            placeholder={this.state.inputValue}
            onChange={this.changeInputValue}
            value={this.inputValue}
            style={{ width: '300px' }}
          />
          <Button type="primary" onClick={this.clickBtn}>添加</Button>
        </div>
        <div style={{ width: '300px' }}>
          <List
            bordered
            dataSource={this.state.list}
            renderItem={(item, index) => (
              <List.Item onClick={this.deleteItem.bind(this, index)}>
                {item}
              </List.Item>
            )
            }
          />
        </div>
      </div>
    );
  }
}
export default TodoListUI;

TodoList.js

import TodoListUI from './TodoListUI'
render() {
  return (
    <TodoListUI />
  );
}

当然现在页面报错,我们接着进行改造

TodoList.js

<TodoListUI 
  inputValue={this.state.inputValue}
  list={this.state.list}
  changeInputValue={this.changeInputValue}
  clickBtn={this.clickBtn}
  deleteItem={this.deleteItem}
/>

TodoListUI.js

render() {
  return (
    <div style={{ margin: '10px' }}>
      <div>
        <Input
          placeholder={this.props.inputValue}
          onChange={this.props.changeInputValue}
          value={this.props.inputValue}
          style={{ width: '300px' }}
        />
        <Button type="primary" onClick={this.props.clickBtn}>添加</Button>
      </div>
      <div style={{ width: '300px' }}>
        <List
          bordered
          dataSource={this.props.list}
          renderItem={(item, index) => (
            <List.Item onClick={this.props.deleteItem.bind(this, index)}>
              {item}
            </List.Item>
          )
          }
        />
      </div>
    </div>
  );
}
把UI组件改成无状态组件可以提高程序性能

TodoListUI.js

import React, { Component } from 'react';
import 'antd/dist/antd.css'
import { Input, Button, List } from 'antd'

const TodoListUI = (props) => {
  return (
    <div style={{ margin: '10px' }}>
      <div>
        <Input
          placeholder={props.inputValue}
          onChange={props.changeInputValue}
          value={props.inputValue}
          style={{ width: '300px' }}
        />
        <Button type="primary" onClick={props.clickBtn}>添加</Button>
      </div>
      <div style={{ width: '300px' }}>
        <List
          bordered
          dataSource={props.list}
          renderItem={(item, index) => (
            <List.Item onClick={() => {props.deleteItem(index)}}>
              {item}
            </List.Item>
          )
          }
        />
      </div>
    </div>
  );
}

export default TodoListUI;

这样,我们的组件就改造好了。

6.请求数据与 redux 结合

请求方式我们使用大家非常熟悉的 axios
npm install --save axios

TodoList.js

import axios from 'axios'
componentDidMount() {
  axios.get('http://musicapi.leanapp.cn/playlist/hot').then((res) => {
    console.log(res)
  })
}

(我自己吧,也不会搭建后台啥的,所以就使用别人的接口,演示而已)😋😋😋😋😋

在这里插入图片描述
数据成功返回了。接下来就是与 redux 的联动了。

actionTypes.js

export const GET_LIST = 'getList'

actionCreators.js

import { GET_LIST } from './actionTypes'

export const getListAction = (data) =>({
  type: GET_LIST,
  data
})

TodoList.js

import {getListAction } from './store/actionCreators'

componentDidMount() {
  axios.get('http://musicapi.leanapp.cn/playlist/hot').then((res) => {
    const action = getListAction(res.data)
    store.dispatch(action)
  })
}

reducer.js

import { GET_LIST } from './actionTypes'

const defaultState = {
  inputValue: '请输入',
  list: []
}
export default (state = defaultState, action) => {
 if (action.type === GET_LIST) {
    let newState = JSON.parse(JSON.stringify(state))
    console.log(action.data.tags)
    newState.list = action.data.tags
    return newState
  }
  return state
}

此时我们需要对 TodoListUI.js 做一些变化,

<List.Item onClick={() => {props.deleteItem(index)}}>
  {item.createTime}
</List.Item>

不出意外的话,你就在页面上面看到一大堆数字。


7. redux-thunk 中间件

Redux-thunk 是这个 Redux 最常用的插件。什么时候会用到这个插件?比如在 Dispatch 一个Action 之后,到达 reducer 之前,进行一些额外的操作,就需要用到 middleware(中间件)。在实际工作中你可以使用中间件来进行日志记录、创建崩溃报告,调用异步接口或者路由。 这个中间件可以使用是 Redux-thunk 来进行增强(当然你也可以使用其它的),它是对 Reduxdispatch 的加强,

想使用,先安装

npm install --save redux-thunk

store / index.js

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import reducer from './reducer'
const store = createStore(
  reducer,
  applyMiddleware(thunk)
)
export default store

以前 actionCreators.js 都是定义好的 action,根本没办法写业务逻辑,有了 Redux-thunk 之后,可以把 TodoList.js 中的 componentDidMount 业务逻辑放到这里来编写。也就是把向后台请求数据的代码放到 actionCreators.js 文件里。那我们需要引入 axios ,并写一个新的函数方法。(以前的action是对象,现在的action可以是函数了,这就是redux-thunk带来的好处)

actionCreators.js

import axios from 'axios'

export const getTodoList = () => {
  return (dispatch) => {
    axios.get('http://musicapi.leanapp.cn/playlist/hot').then((res) => {
      const data = res.data
      const action = getListAction(data)
      dispatch(action)
    })
  }
}

TodoList.js

import { getTodoList } from './store/actionCreators'

componentDidMount() {
  const action = getTodoList()
  store.dispatch(action)
}

8. React-Redux这是一个React生态中常用组件,它可以简化Redux流程

想使用,先安装

npm install --save react-redux

我们删除所有的代码,留下的东西就是我们最初简化之后的代码,src 目录下仅仅剩余一个 index.js

index.js

import React, { Component } from 'react';
class TodoList extends Component {
  render() {
    return (
      <div>
        <div>
          <input />
          <button>提交</button>
        </div>
        <ul>
          <li>react</li>
        </ul>
      </div>
    )
  }
}
export default TodoList;

src 目录下新建 store 文件夹,index.js,reducer.js

index.js

import { createStore } from 'redux'
import reducer from './reducer'
const store = createStore(reducer)
export default store

reducer.js

const defalutState = {
  inputValue: '请输入',
  list: []
}
export default (state = defalutState, action) => {
  return state
}

页面我们已经建好了。接下来就是使用 react-redux

<Provider> 是一个提供器,只要使用了这个组件,组件里边的其它所有组件都可以使用store了,这也是 React-redux 的核心组件了

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList'
import { Provider } from 'react-redux'
import store from './store'

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

这样我们就与 react-redux 建立了连接

使用, connect 连接器的使用

映射关系就是把原来的 state 映射成组件中的 props 属性,比如我们想映射 inputValue 就可以写成如下代码。

import React, { Component } from 'react';
import store from './store'
import { connect } from 'react-redux'

class TodoList extends Component {
  constructor(props) {
    super(props)
    this.state = store.getState()
  }
  render() {
    // ....
}

const stateToProps = (state) => {
  return {
    inputValue: state.inputValue
  }
}

export default connect(stateToProps, null)(TodoList);
修改 store 中的数据

React-redux 顺利的拿到 Store中 数据了。如何改变Store中的数据呢?也就是当我们修改<input>中的值时,去改变 store 数据,UI界面也随之进行改变。

TodoList.js
(绑定 onChange 事件)

<input value={this.props.inputValue} onChange={this.props.inputChange} />
inputChange(e) {
  console.log(e.target.value)
}
export default connect(stateToProps, null)(TodoList);

DispatchToProps就是要传递的第二个参数,通过这个参数才能改变store中的值。

const dispatchToProps = (dispatch) => {
  return {
    inputChange(e) {
      console.log(e.target.value)
    }
  }
}

修改 input

 <input value={this.props.inputValue} onChange={this.props.inputChange} />

把 connect 第二个参数传递过去。

export default connect(stateToProps,dispatchToProps)(TodoList);

TodoList.js
(完整代码)

import React, { Component } from 'react';
import store from './store'
import { connect } from 'react-redux'

class TodoList extends Component {
  constructor(props) {
    super(props)
    this.state = store.getState()
  }
  render() {
    return (
      <div>
        <div>
          <input value={this.props.inputValue} onChange={this.props.inputChange} />
          <button>提交</button>
        </div>
        <ul>
          <li>react redux</li>
        </ul>
      </div>
    );
  }
}
const stateToProps = (state) => {
  return {
    inputValue: state.inputValue
  }
}

const dispatchToProps = (dispatch) => {
  return {
    inputChange(e) {
      console.log(e.target.value)
    }
  }
}

export default connect(stateToProps, dispatchToProps)(TodoList);
派发 store
const dispatchToProps = (dispatch) =>{
    return {
        inputChange(e){
            let action = {
                type:'change_input',
                value:e.target.value
            }
            dispatch(action)
        }
    }
}

reducer.js

const defalutState = {
  inputValue: '请输入',
  list: []
}
export default (state = defalutState, action) => {
  if (action.type === 'change_input') {
    let newState = JSON.parse(JSON.stringify(state))
    newState.inputValue = action.value
    return newState
  }
  return state
}

不出意外,当你输入文字时,控制台会输出相对应的文字。
我们给 button 添加点击事件

<button onClick={this.props.clickButton}>提交</button>
const dispatchToProps = (dispatch) => {
  return {
    inputChange(e) {
      let action = {
        type: 'change_input',
        value: e.target.value
      }
      dispatch(action)
    },
    clickButton() {
      let action = { type: 'add_item' }
      dispatch(action)
    }
  }
}
const defalutState = {
  inputValue: '请输入',
  list: []
}
export default (state = defalutState, action) => {
  if (action.type === 'change_input') {
    let newState = JSON.parse(JSON.stringify(state))
    newState.inputValue = action.value
    return newState
  }

  if (action.type === 'add_item') {
    let newState = JSON.parse(JSON.stringify(state))
    newState.list.push(newState.inputValue)
    newState.inputValue = ''
    return newState
  }
  return state
}

映射关系

const stateToProps = (state) => {
  return {
    inputValue: state.inputValue,
    list: state.list
  }
}

界面渲染

<ul>
  {
    this.props.list.map((item, index) => {
      return (
        <li key={index}>
          {item}
        </li>
      )
    })
  }
</ul>

TodoList.js

import React, { Component } from 'react';
import store from './store'
import { connect } from 'react-redux'

class TodoList extends Component {
  constructor(props) {
    super(props)
    this.state = store.getState()
  }
  render() {
    return (
      <div>
        <div>
          <input value={this.props.inputValue} onChange={this.props.inputChange} />
          <button onClick={this.props.clickButton}>提交</button>
        </div>
        <ul>
          {
            this.props.list.map((item, index) => {
              return (
                <li key={index}>
                  {item}
                </li>
              )
            })
          }
        </ul>
      </div>
    );
  }
}
const stateToProps = (state) => {
  return {
    inputValue: state.inputValue,
    list: state.list
  }
}

const dispatchToProps = (dispatch) => {
  return {
    inputChange(e) {
      let action = {
        type: 'change_input',
        value: e.target.value
      }
      dispatch(action)
    },
    clickButton() {
      let action = { type: 'add_item' }
      dispatch(action)
    }
  }
}

export default connect(stateToProps, dispatchToProps)(TodoList);

实现一个简单的 redux

function createStore(reducer) {
  let currentState;
  let listeners = [];

  function getState() {
    return currentState;
  }

  function subscribe(listener) {
    listeners.push(listener)

    return function unsubscribe() {
      const index = listeners.indexOf(listener);
      listeners.splice(index, 1);
    }
  }

  function dispatch(action) {
    currentState = reducer(currentState, action)

    for (let i = 0; i < listeners.length; i++) {
      const lisenter = listeners[i];
      lisenter()
    }
  }

  return {
    getState,
    subscribe,
    dispatch
  }
}

完美撒花 🎉🎉🎉🎉🎉

参考文章 https://jspang.com/detailed?id=48#toc261

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值