react中用redux进行状态管理

文件目录结构

|-- README.md
|-- package.json
|-- public
|   `-- index.html
|-- src
|   |-- components // 放UI组件,即代码不含redux内容
|   |   `-- counter.js
|   |-- containers // 放容器组件,即代码含redux内容
|   |   `-- App.js
|   |-- index.js
|   `-- redux
|       |-- action-types.js
|       |-- actions.js
|       |-- reducers.js
|       `-- store.js
`-- yarn.lock

需要使用的库和插件

redux

  • 下载
    npm install --save redux
    
  • 使用场景
    • store.js
    import {createStore, applyMiddleware} from 'redux';
    import thunk from 'redux-thunk';
    
    import {counter} from './reducers';
    
    export const store = createStore(
        counter,
        applyMiddleware(thunk)
    );
    
    1. createStore用于创建store对象,store的作用是管理state,actionreducer
    2. applyMiddleware用于应用中间件,如上所示,代码使用了thunk中间件,使redux可以编写异步代码
    • reducers.js
    import {combineReducers} from 'redux';
    
    function counter(state = 0, action) {
      ···
      ···
    }
    
    function counter2(state = 0, action) {
      ···
      ···
    }		
    export default combineReducers({
      counter,
      counter2
    })
    
    // redux向外暴露的state是对象结构
    // {counter: counter的state, counter2: counter2的state}
    
    1. reducers.js只有一个reducer对象,则可以不使用combineReducers方法,直接export defaultreducer对象即可

react-redux

  • 下载

    npm install --save react-redux
    
  • 使用场景

    • index.js
    ···
    import {Provider} from 'react-redux';
    import {store} from "./redux/store";
    ···	
    
    ReactDOM.render(
        <Provider store={store}>
            <App/>
        </Provider>,
        document.getElementById('root')
    );
    
    1. store对象以属性的形式传给Provider组件
    • app.js
    import {connect} from 'react-redux';
    
    import {Counter} from '../components/Counter';
    import {increment, decrement, incrementAsync} from '../redux/actions';
    
    export default connect(
        state => ({count: state}),
        {increment, decrement, incrementAsync}
    )(Counter);
    
    1. 将react和redux进行连接,通过connectstateaction以属性的形式传递给Counter组件

redux-thunk

  • 下载
    npm install --save redux-thunk
    
  • 使用场景
    • store.js
    import {createStore, applyMiddleware} from 'redux';
    import thunk from 'redux-thunk';
    
    import {counter} from './reducers';
    
    export const store = createStore(
        counter,
        applyMiddleware(thunk)
    );
    
    1. thunk以中间件的形式添加到store对象中,使原本不支持异步的redux支持异步代码

prop-types(可选)

  • 下载
    npm install --save prop-types
    
  • 使用场景
    • Counter.js
    export class Counter extends Component{
      static propTypes = {
        count: PropTypes.number.isRequired,
        increment: PropTypes.func.isRequired,
        decrement: PropTypes.func.isRequired,
        incrementAsync: PropTypes.func.isRequired
      }
      ···
      render(){
    	  return (
    	  ···
    	)
    }
    
    1. 非必要步骤,但是添加propTypes事先声明props中含有的属性值,更加严谨

redux-devtools-extension(用于redux调试)

  • 下载
    npm install --save-dev redux-devtools-extension
    
  • 使用场景
    • store.js
    import {composeWithDevTools} from 'redux-devtools-extension';
    ······
    
    export const store = createStore(
        counter,
        composeWithDevTools(applyMiddleware(thunk))
    );
    
    1. 需要配合Chrome插件ReduxDevTools进行使用

src/下各文件的内容

src/redux/action-types.js

  • 存放固定的常量信息,在需要的文件中进行引用,以防拼写出错
    export const INCREMENT = "increment";
    export const DECREMENT = "decrement";
    

src/redux/actions.js

  • 存放生成action的工厂函数,同步代码返回对象,异步代码返回函数(前提是使用上了redux-thunk
    // 从action-types中引入常量
    import {INCREMENT, DECREMENT} from "./action-types";
    
    // 同步代码,返回对象
    export const increment = (data) => ({type: INCREMENT, data});
    export const decrement = (data) => ({type: DECREMENT, data});
    
    // 异步代码,返回函数
    export const incrementAsync = (data) => {
        return dispatch => {
            setTimeout(()=>{dispatch(increment(data))}
            ,1000)
        }
    };
    

src/redux/reducers.js

  • 存放reducer,用于在store.js文件中引用并生成store对象
    import {combineReducers} from 'redux';
    
    // 从action-types中引入常量
    import {INCREMENT, DECREMENT} from "./action-types";
    
    export function counter(state=0, action) {
        switch (action.type) {
            case INCREMENT:
                return state + action.data;
            case DECREMENT:
                return state - action.data;
            default:
                return state
        }
    }
    export default combineReducers({
    	  counter
    })
    

src/redux/store.js

  • 生成store对象,并向外暴露给index.js
    import {createStore, applyMiddleware} from 'redux';
    import thunk from 'redux-thunk';
    import {composeWithDevTools} from 'redux-devtools-extension';
    
    import reducers from './reducers';
    
    export const store = createStore(
        reducers,
        composeWithDevTools(applyMiddleware(thunk))
    );
    

src/components/Counter.js

  • UI组件
    import React, {Component} from 'react';
    import {PropTypes} from 'prop-types';
    
    export class Counter extends Component{
      static propTypes = {
        count: PropTypes.number.isRequired,
        increment: PropTypes.func.isRequired,
        decrement: PropTypes.func.isRequired,
        incrementAsync: PropTypes.func.isRequired
      }
    
      increment = () => {
        const val = this.select.value*1;
        this.props.increment(val)
      }
    
      decrement = () => {
        const val = this.select.value*1;
        this.props.decrement(val)
      }
    
      incrementAsync = () => {
        const val = this.select.value*1;
        this.props.incrementAsync(val)
      }
    
      render() {
        const count = this.props.count;
    
        return (
            <div>
              <p>click {count} times</p>
              <div>
                <select ref={select => this.select = select}>
                  <option value="1">1</option>
                  <option value="2">2</option>
                  <option value="3">3</option>
                </select>
                &nbsp;
                <button onClick={this.increment}>+</button>&nbsp;
                <button onClick={this.decrement}>-</button>
                <button onClick={this.incrementAsync}>incrementAsync</button>
              </div>
            </div>
        );
      }
    }
    

src/containers/App.js

  • 容器组件,由于reducers.js使用了combineReducers,所以connect函数中要通过state.counter指定使用哪个state;若reducers.js只有一个reducer且没有使用combineReducers,则以下代码的state.counter改成state即可
    import {connect} from 'react-redux';
    
    import {Counter} from '../components/Counter';
    import {increment, decrement, incrementAsync} from '../redux/actions';
    
    export default connect(
        state => ({count: state.counter}), // mapStateToprops
        {increment, decrement, incrementAsync} // mapDispatchToProps
    )(Counter);
    

总结

|-- README.md
|-- package.json
|-- public
|   `-- index.html
|-- src
|   |-- components // 放UI组件,即代码不含redux内容
|   |   `-- counter.js // 不需要使用redux相关库
|   |-- containers // 放容器组件,即代码含redux内容
|   |   `-- App.js // 使用react-redux({connect})
|   |-- index.js // 使用react-redux({Provider})
|   `-- redux
|       |-- action-types.js
|       |-- actions.js
|       |-- reducers.js // 使用redux({combineReducers})
|       `-- store.js // 使用redux({createStore, applyMiddleware}), redux-thunk(thunk), redux-devtools-extension({composeWithDevTools})
`-- yarn.lock
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值