redux

96 阅读2分钟

redux

单向数据流

function createStore(reducer) {
    var state;
    var listeners = [];
    var getState = () => state;
    var dispatch = (action) => {
        state = reducer(state, action);
        listeners.forEach(l=>l());
    }
    var subscribe = (listener) => {
        listeners.push(listener);
        return () => {
            listeners = listeners.filter((l) => l != listener)
        }
    }
    dispatch();
    return {
        getState, dispatch, subscribe
    }
}
var reducer = (state = 0, action) => {
    if (!action) return state;
    console.log(action);
    switch (action.type) {
        case 'INCREMENT':
            return state + 1;
        case 'DECREMENT':
            return state - 1;
        default:
            return state;
    }
}
var store = createStore(reducer);
store.subscribe(function () {
    document.querySelector('#counter').innerHTML = store.getState();
});
// listener可以通过store.getState()得到当前状态。如果使用的是 React,这时可以触发重新渲染 View。
// function listerner() {
//   let newState = store.getState();
//   component.setState(newState);   
// }

document.querySelector('#addBtn').addEventListener('click', function () {
    store.dispatch({type: 'INCREMENT'});
});
document.querySelector('#minusBtn').addEventListener('click', function () {
    store.dispatch({type: 'DECREMENT'});
});

class组件用 react-redux

connect

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'

let store = createStore(todoApp)

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






import { connect } from 'react-redux'

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

函数组件用 redux

useSelector, useDispatch

 import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { updateTel, updateName } from './action'

export default () => {
  const formData = useSelector(state => {
    console.log('--xia-', state);

    return state
  })
  console.log({formData});

  const dispatch = useDispatch()

  return <div>
      form: <br/>
      姓名: <input type="text" onChange={(e) => {
        dispatch(updateName(e.target.value))
      }}/>
      电话: <input type="tel" onChange={(e) => {
        dispatch(updateTel(e.target.value))
      }}/>
  </div>

}

异步

redux默认不支持异步,需要插件才能实现 cnpm install --save redux-thunk

1、在store.js中,引入中间件,并使用

import {createStore,applyMiddleware} from 'redux';
import thunk from 'redux-thunk'
const store=createStore(counter,applyMiddleware(thunk))

2、在action-type中定义action常量名,并设置与异步状态相关的同步action

export const xx=(参数)=>{return dispatch=>{
    异步操作,获取数据后调用同步方法改变状态
    dispatch(同步action方法(参数))
}}

3、引入对应的变量名等操作...

actions.js

import { INCREMENT,DECREMENT } from "./action-type";

//同步action返回对象
export const increment=(num)=>({type:INCREMENT,data:num})
export const decrement=(num)=>({type:DECREMENT,data:num})
//异步action返回函数
export const incrementAsync=(num)=>{return dispatch=>{
    setTimeout(()=>{
        dispatch(increment(num))
    },1000)
}}

store.js:

import {createStore,applyMiddleware} from 'redux';
import  {counter} from './reducers'
import thunk from 'redux-thunk'

const store=createStore(counter,applyMiddleware(thunk))//第二个参数指定应用上的中间件
console.log(store);

export default store;

app.js

import React from 'react';
import './App.css';
import {increment,decrement,incrementAsync}  from './redux/actions'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'

class App extends React.Component{

  static propTypes={
    count:PropTypes.number.isRequired,
    increment:PropTypes.func.isRequired,
    decrement:PropTypes.func.isRequired,
    incrementAsync:PropTypes.func.isRequired
  }
increment = () => {
    const num = this.refs.numSelect.value*1
    // this.props.store.dispatch(actions.increment(num));
    this.props.increment(num);
  }

  decrement = () => {
    const num = this.refs.numSelect.value*1
   
    // this.props.store.dispatch(actions.decrement(num))
    this.props.decrement(num);
  }

  incrementIfOdd = () => {
    const num = this.refs.numSelect.value*1
    // const count=this.props.store.getState();
    const count=this.props.count

    if(count%2==1) {
      this.props.increment(num);
    }
  }
  
  	//异步调用
  incrementAsync = () => {
    const num = this.refs.numSelect.value*1
    this.props.incrementAsync(num);
  }

  render () {
    // const count = this.props.store.getState()

    const count =this.props.count;

    return (
      <div>
        <p>
          click {count} times {' '}
        </p>
        <select ref="numSelect">
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
          </select>{' '}
        <button onClick={this.increment}>+</button>{' '}
        <button onClick={this.decrement}>-</button>{' '}
        <button onClick={this.incrementIfOdd}>increment if odd</button>{' '}
        <button onClick={this.incrementAsync}>increment async</button>
      </div>
    )

  }

}

export default connect(
  state=>({ count:state }),
  {increment,decrement,incrementAsync}
)(App); //connect()返回一个类,第一次参数为函数,第二个参数为对象,接收参数是App组件

//第一个参数根据redux中的状态,创建变量来接收,变量也会被解构放入App标签,当作组件参数传递
//第二个参数中的内容,会被...解构当作参数传递给组件App