回顾: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

版权声明:本文为zhongchao666原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/zhongchao666/p/9478008.html