zoukankan      html  css  js  c++  java
  • 25.redux回顾,redux中的action函数异步

    回顾:Redux: 类似于 Vuex

    概念:store/reducer/action

    action:动作 {type,.....} 一定要有type 其他属性不做限制

    reducer:通过计算产生state
    公式:(state,action)=>newState

    store: 容器

    getState() 获取所有状态

    dispatch(action) dispatch里面可以跟对象和函数, —— 函数需要单独处理——中间件
    subscribe(监听函数);—— watch

    触发条件:
    1、dispatch ---> reducer
    2、必须产生一个新的状态 newState

    exp1:

    1.ction.js
    export const PLUS = Symbol("PLUS");
    export const MINUS = Symbol("MINUS");
    
    export function plusAction(){
        return {type:PLUS};
    }
    export function minusAction(){
        return {type:MINUS};
    }
    
    2.reducer.js
    
    import {PLUS} from "./actions"
    //数据初始化
    const initState = {count:1};
    
    //创建reducer
    const reducer = (state = initState,action = {})=>{
        const {type} = action;
        switch(type){
            case PLUS:
                return {...state,count:state.count+1};
            default:
                return state;
        }
    }
    export default reducer;
    
    3.store
    
    //引入
    import {createStore} from "redux";
    import reducer from "./reducer";
    //创建store
    const store = createStore(reducer);
    store.subscribe(()=>console.log(store.getState()));
    export default store;
    
    4.App.js
    
    import React, { Component } from 'react';
    class App extends Component {
      render() {
        return (
          <div className="App">
            App
          </div>
        );
      }
    }
    export default App;
    
    5.Counter.js
    
    //引入
    import React,{Component} from "react";
    import {bindActionCreators} from "redux";
    import {connect} from "react-redux";
    import {plusAction,minusAction} from "./actions";
    
    //创建组件
    class Counter extends Component{
        render(){
            console.log(11111,this.props);
            const {count,plusAction} = this.props;
    
            return (
                <div>
                    {count}
                    <input onClick={plusAction} value="+" type="button"/>
                </div>
            );
        }
    }
    
    const mapStateToProps = state =>({
        count:state.count
    });
    
    function mapDispatchToProps(dispatch){
        return bindActionCreators({plusAction,minusAction},dispatch);
    }
    
    export default connect(mapStateToProps,mapDispatchToProps)(Counter);
    
    
    react-redux: {Provider,connect}

    Provider:提供 作用: 把状态 store共享给所有的子组件 包在

    connect 用法: connect()(Comp); ---> this.props --> {dispatch}

    connect(mapStateToProps,xxxxxxx)(Comp); ---> this.props -->{ state, dispatch }
    

    exp1:

    index.js
    
    import React from 'react';
    import ReactDOM from 'react-dom';
    import {Provider} from "react-redux";
    
    import store from "./Counter/store";
    import App from "./Counter/App";
    import registerServiceWorker from './registerServiceWorker';
    
    ReactDOM.render(
        <Provider store={store}>
            <App />
        </Provider>,
        document.getElementById('root'));
    
    registerServiceWorker();
    
    

    image

    异步action —— 在原有的异步函数内 包个函数—— 函数会有一个dispatch参数

    在action里面有延迟操作!定时器、数据交互(ajax,fetch...)

    用redux-thunk
    第一步:

    1、安装 cnpm i -S redux-thunk
    2、引入 import thunk from "redux-thunk";
    3、redux中引入applyMiddleware
    import {createStore,applyMiddleware} from "redux";
    4、const store = createStore(reducer,applyMiddleware(thunk));

    第二步:

    ++在异步anctions中使用++
    问题1:

    ++定时器++

    function plusAsyncAction(){
    	setTimeout(()=>{  
    			return {type:"PLUS"};
    	},1000);
    }
    

    通过中间件来解决

    function plusAsyncAction(){
    	return function(dispatch){
    		setTimeout(()=>{
    			  //自己手动派发action
    				dispatch({type:"PLUS"});
    		},1000);
    	}
    }
    

    exp1:
    import {createStore,applyMiddleware} from "redux";引入模块
    const store = createStore(reducer,applyMiddleware(thunk)); 使用模块

    import React,{Component} from "react";
    import {createStore,applyMiddleware} from "redux";
    import thunk from "redux-thunk";
    
    //创建store
    //数据初始化
    const initState = {count:1};
    
    //创建reducer
    const reducer = (state=initState,action={})=>{
        const {type} = action;
        switch(type){
            case "PLUS":
                return {...state,count:state.count+1};
            default:
                return state;
        }
    }
    
    //创建store
    const store = createStore(reducer,applyMiddleware(thunk));
    
    function plusAction(){
        return {type:"PLUS"};
    }
    
    function plusAsyncAction(){
        return function(dispatch,getState){
            const val = getState();//获取是修改之前的状态
            console.log(val,getState);
            setTimeout(()=>{
                //dispatch({type:"PLUS"});
                dispatch(plusAction());
            },1000)
        }
    }
    
    class Counter extends Component{
    
        constructor(...args){
            super(...args);
            store.subscribe(()=>{
                console.log(store.getState());
                this.forceUpdate();
            });
        }
    
        plus(){
            store.dispatch(plusAsyncAction());
        }
        render(){
            return (
                <div>
                    {store.getState().count}
                    <input onClick={this.plus.bind(this)} value="+" type="button"/>
                </div>
            );
        }
    }
    export default Counter;
    

    res:
    延迟一秒显示
    image


    问题2:

    ++交互(数据交互(ajax,fetch...))++

    function fetchAsyncAction(){
    		
    		fetch(url).then.then(data=>{
    			
    			return {type:"GET",payload:data};
    		
    		})
    		
    		//return undefined
    }
    

    通过中间件来解决

    function fetchAsyncAction(){
    		
    		return function(dispatch){
    			fetch(url).then.then(data=>{
    				dispatch({type:"GET",payload:data});
    			})
    		}
    }
    

    exp2:
    数据交互

    import React,{Component} from "react";
    import {createStore,applyMiddleware} from "redux";
    import thunk from "redux-thunk";
    const url = "http://localhost:9000/api/v2/movie/in_theaters?city=北京";
    //创建store
    //数据初始化
    const initState = {subjects:[]};
    //创建reducer
    const reducer = (state = initState,action = {})=>{
        const {type} = action;
        switch(type){
            case "GET":
                return {...state,subjects:action.payload};
            default:
                return state;
        }
    }
    //创建store
    const store = createStore(reducer,applyMiddleware(thunk));
    
    function fetchSyncAction(){
        return function(dispatch){
            fetch(url).then(res=>res.json()).then(data=>{
                console.log(data.subjects);
                dispatch({type:"GET",payload:data.subjects});
            })
        }
    }
    
    //创建组件
    class Fetch extends Component{
        constructor(...args){
            super(...args);
            store.subscribe(()=>{
                console.log(store.getState());
                this.forceUpdate();
            })
        }
        asyncFecth(){
            store.dispatch(fetchSyncAction());
        }
        fn(){
    
            //url:"http://api.douban.com/v2/movie/in_theaters?city=北京",
            //url:"http://localhost:9000/api/v2/movie/in_theaters?city=北京",
            
            //store.dispatch(plusAsyncAction());
            fetch(url).then(res=>res.json()).then(data=>{
                console.log(data.subjects);
    
                store.dispatch({type:"GET",payload:data.subjects});
            })
        }
    
        render(){
            return (
                <div>
                    {
                       store.getState().subjects.map(({id,title})=>{
                        return <div key={id}>{title}</div>;
                        })
                    }
                    <input onClick={this.fn.bind(this)} value="普通fetch" type="button"/>
                    <input onClick={this.asyncFecth.bind(this)} value="asyncFecth" type="button"/>
                </div>
            );
        }
    
    }
    
    export default Fetch;
    

    res:
    image

            dispatch(action)                 
    View  ------------------->  reducer ---------> newState 
    
    
                异步                                同步
           dispatch(asyncAction)                 dispatch(action)
    View  ----------------------> middleware拦截 --------------->  reducer --------> newState
    

    属性验证:

    安装:cnpm i -D prop-types

    参考:https://reactjs.org/docs/typechecking-with-proptypes.html?#___gatsby

    Test.propTypes = {
    		属性:验证规则
    		optionalArray: PropTypes.array,
    	  optionalBool: PropTypes.bool,
    	  optionalFunc: PropTypes.func,
    	  optionalNumber: PropTypes.number,
    	  optionalObject: PropTypes.object,
    	  optionalString: PropTypes.string,
    	  optionalSymbol: PropTypes.symbol,
    
    		
    }
    

    exp1:

    import React, { Component } from "react";
    import PropTypes from "prop-types";
    
    class Test extends Component {
        //判断name是否是字符串,若不是字符串则报错
        //,isRequired表示空也判断
        //写法二
        static propTypes = {
            name: PropTypes.string.isRequired,
        }
        
      render() {
          const {name} = this.props;
        return (
          <div>属性验证:name: {name}</div>
        );
      }
    }
    //写法一
    /*Test.propTypes = {
        name: PropTypes.string.isRequired,
    }*/
    
    export default Test;
    
    

    res:
    符合判定不返回任何值,不符合则会报错,并提醒输入的是何种类型数据.

    image

    exp2:
    自定义属性验证

    import React, { Component } from "react";
    // import PropTypes from "prop-types";
    
    function Test(props){
        return (
          <div>属性验证:name: {props.name}</div>
        );
    }
    
    const PropTypes = {
        string:function(props, propName, componentName){
            if(typeof props[propName] !== "string"){
                return new Error(`你输入的${propName}我期望的是 字符串 ,但是你给我的是 ${typeof props[propName]} `);
            }
    
        }
    }
    
    Test.propTypes = {
        name:PropTypes.string,
    }
    export default Test;
    

    res:
    image

    在异步anctions中使用的案例
    豆瓣网:

    image

    代码:

    1.App.js
    
    import React, { Component } from "react";
    import { Provider} from "react-redux";
    import store from "./store";
    import MoveBox from "./MoveBox";
    import "./index.css";
    let arr = [
      {id:1,city:"北京"},
      {id:2,city:"上海"},
      {id:3,city:"深圳"},
      {id:4,city:"青岛"}
    ];
    
    class App extends Component {
      render() {
        return (
          <Provider store={store}>
            <div className="App">
              <MoveBox arr={arr}/>
            </div>
          </Provider>
        );
      }
    }
    export default App;
    -----------------------------------
    2.index.css
    
    .active{background:pink;}
    -----------------------------------
    3.reducer.js
    
    import {QUERY} from "./actions"
    
    const initState = {
        id:1,
        city:"北京"
    };
    
    export default (state = initState,action = {})=>{
        switch(action.type){
            case QUERY:
                return {...state,id:action.payload.id,city:action.payload.city};
            default:
                return state;
        }
    
    };
    -------------------------------
    
    4.store.js
    import {createStore, applyMiddleware} from "redux";
    import thunk from "redux-thunk";
    import reducer from "./reducer";
    const store = createStore(reducer,applyMiddleware(thunk));
    
    //测试用
    store.subscribe(()=>{
        console.log("store:",store.getState())
    });
    
    export default store;
    ----------------------------------
    5.action.js
    
    export const QUERY = Symbol("QUERY");
    
    ------------------------------------
    6.MoveBox.js
    import React, { Component } from "react";
    import { connect } from "react-redux";
    import MoveTitle from "./MoveTitle";
    import MoveList from "./MoveList";
    
    //url:"http://api.douban.com/v2/movie/in_theaters?city=北京",
    //url:"http://localhost:9000/api/v2/movie/in_theaters?city=北京",
    class MoveBox extends Component {
      render() {
          console.log("this.props:",this.props);
          const {id,city,arr} = this.props;
        return (
          <div>
            <MoveTitle id={id} arr={arr}/>
            <MoveList city={city} />
          </div>
        );
      }
    }
    
    function mapStateToProps(state){
        return {id:state.id,city:state.city};
    }
    
    export default connect(mapStateToProps)(MoveBox);
    -------------------------------------------
    7.MoveTitle.js
    import React, { Component } from "react";
    import { connect } from "react-redux";
    import { QUERY } from "./actions";
    class MoveTitle extends Component {
    
    
        fn(item){
            this.props.dispatch({type:QUERY,payload:item});
        }
    
      render() {
          const {id,arr} = this.props; 
        return (
          <ul> 
              {
                  arr.map(item=>{
                      return <input onClick={this.fn.bind(this,item)} className={item.id === id?"active":""} key={item.id} type="button" value={item.city}/>
                  })
              }
              
          </ul>
        );
      }
    }
    
    export default connect()(MoveTitle);
    
    --------------------------------------
    8.MoveList.js
    import React, { Component } from "react";
    
    //http://localhost:9000/api/v2/movie/in_theaters?city=北京",
    
    const url = "http://localhost:9000/api/v2/movie/in_theaters?city=";
    
    class MoveList extends Component {
    
        state = {title:this.props.city,subjects:[]};
    
        UNSAFE_componentWillReceiveProps(props){
    
            console.log("UNSAFE_componentWillReceiveProps",props,this.props);
            this.featcData(props.city);
        }
        componentDidMount(){
            this.featcData();
        }
    
        featcData(city){
            city = city||this.props.city
            fetch(`${url}${city}`).then(res=>res.json()).then(data=>{
                console.log(111,data);
                this.setState(data);
            });
        }
      render() {
        return (
          <div> 
            {this.state.title}
            <hr />
            <ul>
                {
                    this.state.subjects.map(item=>{
                        return <li key={item.id}>{item.title}</li>
                    })
                }
            </ul>
    
    
          </div>
        );
      }
    }
    
    export default MoveList;
    
    

    res:
    image

  • 相关阅读:
    基于 html5的 jquery 轮播插件 flickerplate
    grafana配置
    grafana-zabbix部署和使用
    nxlog windows安装部署
    InfluxDB、grafana、collect部署监控(centos6.8)
    InfluxDB基本概念和操作
    InfluxDB1.2.4部署(centos6.8)
    grafana worldPing插件
    prometheus + grafana部署RabbitMQ监控
    prometheus + grafana安装部署(centos6.8)
  • 原文地址:https://www.cnblogs.com/zhongchao666/p/9478008.html
Copyright © 2011-2022 走看看