React从入门到实战- 企业级实战项目-宜居二

2019年最新 React从入门到实战(带 React 企业级实战项目-宜居)

(React-Redux基础知识&)

React-Redux基础知识&

41.Redux 回顾组件传递及Redux介绍

(Redux 回顾组件传递及Redux介绍&)

Redux 回顾组件传递及Redux介绍&

父传子

子传父

接收数据

默认什么都没有点击传值

普通情况只能组件间传递数据,redux子组件把数据传递给仓库,store负责把数据分发各个组件

把数据提交到公共的stroe仓库中

组件间通信

src\components\coms\Parent.jsx

import React from "react"
import Child from "./Child"

export default class Parent extends React.Component{

    state = {
        value:""
    }

    clickHandle = (data) =>{
        this.setState({
            value:data
        })
    }

    render(){
        return(
            <div>
                Parent:{ this.state.value }
                <Child title="子标题" onMyEvent={ this.clickHandle }/>
            </div>
        )
    }
}

src\components\coms\Child.jsx

import React from "react"

export default class Child extends React.Component{

    clickHandle = (e) =>{
        this.props.onMyEvent("父标题");
    }
    
    render(){
        return(
            <div>
                Child:{ this.props.title }
                <button onClick={ this.clickHandle }>传递数据</button>
            </div>
        )
    }
}

App.js

import React from 'react';
import Parent from "./components/coms/Parent"
import { connect } from "react-redux"
// import { increment,decrement } from "./actions/counter"
import * as counterActions from "./actions/counter"
import { bindActionCreators } from "redux"
import User from "./components/user"

class App extends React.Component {
    render(){
        return (
            <div className="container">
                {/* <Parent/> */}
                <h1 className="jumbotron-heading text-center">{ this.props.counter }</h1>
                <p className="text-center">
                    {/* <button onClick={ this.props.onIncrement } className="btn btn-primary">increment</button>
                    <button onClick={ this.props.onDecrement } className="btn btn-success">decrement</button> */}
                    {/* <button onClick={ () => (increment()) } className="btn btn-primary">increment</button>
                    <button onClick={ () => (decrement()) } className="btn btn-success">decrement</button> */}
                    <button onClick={ () => this.props.counterActions.increment(10) } className="btn btn-primary">increment</button>
                    <button onClick={ () => this.props.counterActions.decrement(5) } className="btn btn-success">decrement</button>
                </p>
                <User />
            </div>
        );
    }
}

const mapStateToProps = (state) =>{
    console.log(state);
    
    return{
        counter:state.counter
    }
}

// const mapDispatchToProps = (dispatch) =>{
//     return {
//         increment: () => { dispatch(increment()) },
//         decrement: () => { dispatch(decrement()) }
//     }
// }

const mapDispatchToProps = (dispatch) =>{
    return{
        counterActions:bindActionCreators(counterActions,dispatch)
    }
}

// 先后顺序不能颠倒
export default connect(mapStateToProps,mapDispatchToProps)(App)

index.js

createStore

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { createStore,applyMiddleware } from "redux"
import { composeWithDevTools } from 'redux-devtools-extension';
import logger from "redux-logger"
import thunk from "redux-thunk"
// import reducer from "./reducers/counter"
import { Provider } from "react-redux"
import rootReducer from "./reducers"

// 异步和同步
// 定时器  网络请求


// 中间件
// const logger = store  => next => action =>{
//     console.log("dispatch->",action);
//     let result = next(action); // 加载下一个中间件
//     console.log("next state->",store.getState());
//     return result;
// }

// const error = store => next => action => {
//     try{
//         next(action)
//     }catch(e){
//         console.log("error->",e);
//     }
// }

// 创建store仓库
// const store = createStore(rootReducer,{},applyMiddleware(logger,error));
const store = createStore(rootReducer,{},composeWithDevTools(applyMiddleware(logger,thunk)));
// store.subscribe(() => console.log("state:", store.getState()))

// const render = () => {
//     ReactDOM.render(
//         <App
//             onIncrement={() => store.dispatch({ type: "INCREMENT" })}
//             onDecrement={() => store.dispatch({ type: "DECREMENT" })}
//             value={store.getState()}
//         />,
//         document.getElementById('root'));

// }
// render();
// store.subscribe(render)




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

42.BootStrap CDN加载

(BootStrap CDN加载&)

BootStrap CDN加载&

CDN加载

引入CDN

编写视图

react-redux-demo\public\index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>

43.Redux 引入Redux

(Redux 引入Redux&)

Redux 引入Redux&

Redux应用的是单一的stroe

Reducer存在stroe中改变状态的方案

Reducer写法,state往仓库中存的状态,默认state为0,action.type不同的状态改变state

Store.dispatch触发来更新state的

reducer点击触发action.type,在App接收触发两个事件,action动作要对应到reducer一样的字符。

监听数据的变化,store.getState读取到数据

subscribe监听数据变化

渲染到页面上

要重新渲染,首先要render()以后每次监听数据变化要重新渲染render

重新渲染render

src\reducers\counter.js

reducer

import * as actions from "../constants"

const counter = ( state = 0,action ) => {
    switch(action.type){
        case actions.INCREMENT:
            // throw new Error("error reducer")
            return state + action.num;
        case actions.DECREMENT:
            return state - action.num;
        default:
            return state;
    }
}

export default counter

src\constants\index.js

// counter
export const INCREMENT = "INCREMENT"
export const DECREMENT = "DECREMENT"

// user
export const FETCH_USER_SUCCESS = "FETCH_USER_SUCCESS"
export const FETCH_USER_REQUEST = "FETCH_USER_REQUEST";
export const FETCH_USER_FAILURE = "FETCH_USER_FAILURE";

44.Redux 引入React-Redux与mapStateToProps读取数据

(Redux 引入React-Redux与mapStateToProps读取数据&)

Redux 引入React-Redux与mapStateToProps读取数据&

组件通过Mouse触发到Provider身上形成多个Actions动作,触发store当中的reducer,reducer就会发生改变,有多少个action就会对应多少store和reducer

Provider用来包裹的关联上redux和react,不要任何的操作了,单纯应用App,需要store对象

通过Provider本身额外的操作,store是刚刚创建的store,通过provider关联react和redux

react-redux

组件中读取数据

通过connect把App组件与redux连接起来。

按钮操作的两个事件,外面没有传递操作事件了。

mapStateToProps对象读取数据的方案,通过state参数,counter中能读到数据,放到connect()中。Connect连接组件与redux,读取数据

mapStateToProps读取数据

State本身就是counter的值

读取数据要从props中读到数据

45.Redux dispatch与mapDispatchToProps修改数据方案

(Redux dispatch与mapDispatchToProps修改数据方案&)

Redux dispatch与mapDispatchToProps修改数据方案&

操作和修改数据通过dispatch,要单独创建action操作,要提取action操作方便后期维护

Return type值

引入action的操作对象

mapDispatchToProps用来分发事件的,dispatch触发事件的

注意Connect的顺序不能颠倒

dispatch触发action

Props中有了increment

通过dispatch触发increment()函数,需要props

没有dispatch可以触发函数,props中有increment函数

src\actions\counter.js

import * as actions from "../constants"
// export function increment(num){
//     return{
//         type:actions.INCREMENT,
//         num
//     }
// }

export function increment(num){
    return dispatch => {
        setTimeout(() =>{
            dispatch({
                type:actions.INCREMENT,
                num
            })
        },1000)
    }
}


export function decrement(num){
    return{
        type:actions.DECREMENT,
        num
    }
}

46.Redux bindActionCreators与参数传递

(Redux bindActionCreators与参数传递&)

Redux bindActionCreators与参数传递&

Action中有很多的操作另一种方式,写起来更容易一些

mapDispatchToProps操作方法变简单了,通过bindActionCreators绑定所有的actions

操作方法简单了,操作按钮修改,通过this.props.counterActions中的increment方法操作,事件触发不是触发函数了。

方法的字符串要有reducer的action.type对应,不用写非常多的actions动作。

字符串要对应,通过常量文件夹管理。

常量字符串,action参数传递

直接引用

按照指定数字增加与减少,参数传递,参数传递给了action,操作的是actions

真正操作的是reducer,前后一样可以省略

参数传递,直接通过前台数据传递到后台actions,通过actions响应到reducers,接收数据

src\actions\counter.js

import * as actions from "../constants"
// export function increment(num){
//     return{
//         type:actions.INCREMENT,
//         num
//     }
// }

export function increment(num){
    return dispatch => {
        setTimeout(() =>{
            dispatch({
                type:actions.INCREMENT,
                num
            })
        },1000)
    }
}


export function decrement(num){
    return{
        type:actions.DECREMENT,
        num
    }
}

src\reducers\counter.js

import * as actions from "../constants"

const counter = ( state = 0,action ) => {
    switch(action.type){
        case actions.INCREMENT:
            // throw new Error("error reducer")
            return state + action.num;
        case actions.DECREMENT:
            return state - action.num;
        default:
            return state;
    }
}

export default counter

47.Redux combineReducers合并reducer

(Redux combineReducers合并reducer&)

Redux combineReducers合并reducer&

State中有很多条数据,很多数据需要共享,要合并reducer

通过combineReducers来合并reducers

外层引用关系不需要引用reducer了,直接引用rootReducers

此时相当于给counter多加了一个对象,state代表一个对象,要读取state里面的counter

新增User组件在App中引用

User数据也是共享的,为User也创建一系列的数据

State中有多条数据了

combineReducers合并reducers

src\reducers\index.js

import { combineReducers } from "redux"
import counter from "./counter"
import user from "./user"

const rootReducer = combineReducers({
    counter,
    user
})

export default rootReducer

src\reducers\user.js

import { FETCH_USER_SUCCESS,FETCH_USER_REQUEST, FETCH_USER_FAILURE } from "../constants"

const initialState = {
    user:{},
    isFetching: false,
    error: null,
}

const user = ( state = initialState,action ) => {
    switch(action.type){
        case FETCH_USER_SUCCESS:
            return {
                isFetching: false,
                error: null,
                user: action.user
            };
        case FETCH_USER_REQUEST:
            return {
                isFetching: true,
                error: null,
                user: {}
            }
        case FETCH_USER_FAILURE:
            return {
                isFetching: false,
                error: action.error,
                user: {}
            };
        default:
            return state;
    }
}

export default user

App.js

import React from 'react';
import Parent from "./components/coms/Parent"
import { connect } from "react-redux"
// import { increment,decrement } from "./actions/counter"
import * as counterActions from "./actions/counter"
import { bindActionCreators } from "redux"
import User from "./components/user"

class App extends React.Component {
    render(){
        return (
            <div className="container">
                {/* <Parent/> */}
                <h1 className="jumbotron-heading text-center">{ this.props.counter }</h1>
                <p className="text-center">
                    {/* <button onClick={ this.props.onIncrement } className="btn btn-primary">increment</button>
                    <button onClick={ this.props.onDecrement } className="btn btn-success">decrement</button> */}
                    {/* <button onClick={ () => (increment()) } className="btn btn-primary">increment</button>
                    <button onClick={ () => (decrement()) } className="btn btn-success">decrement</button> */}
                    <button onClick={ () => this.props.counterActions.increment(10) } className="btn btn-primary">increment</button>
                    <button onClick={ () => this.props.counterActions.decrement(5) } className="btn btn-success">decrement</button>
                </p>
                <User />
            </div>
        );
    }
}

const mapStateToProps = (state) =>{
    console.log(state);
    
    return{
        counter:state.counter
    }
}

// const mapDispatchToProps = (dispatch) =>{
//     return {
//         increment: () => { dispatch(increment()) },
//         decrement: () => { dispatch(decrement()) }
//     }
// }

const mapDispatchToProps = (dispatch) =>{
    return{
        counterActions:bindActionCreators(counterActions,dispatch)
    }
}

// 先后顺序不能颠倒
export default connect(mapStateToProps,mapDispatchToProps)(App)

user.jsx

import React from "react"
import { connect } from "react-redux"
import { bindActionCreators } from "redux"
import * as userActions from "../actions/user"

class User extends React.Component{

    render(){

        const { error, isFetching, user } = this.props.user;

        let data;

        if (error) {
            data = error;
        } else if (isFetching) {
            data = "Loading...";
        } else {
            data = user.title;
        }

        return(
            <div className="continer text-center">
                <p className="text-center">{ data }</p>
                <p className="text-center">User</p>
                <button className="btn btn-primary" onClick={ () => { this.props.userActions.get_user() } }>getUser</button>
            </div>
        )
    }
}

const mapStateToProps = (state) =>{
    return{
        user:state.user
    }
}

const mapDispatchToProps = (dispatch) =>{
    return {
        userActions:bindActionCreators(userActions,dispatch)
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(User)

48.Redux Redux中间件与第三方中间件logger

(Redux Redux中间件与第三方中间件logger&)

Redux Redux中间件与第三方中间件logger&

logger中间件

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { createStore,applyMiddleware } from "redux"
import { composeWithDevTools } from 'redux-devtools-extension';
import logger from "redux-logger"
import thunk from "redux-thunk"
// import reducer from "./reducers/counter"
import { Provider } from "react-redux"
import rootReducer from "./reducers"

// 异步和同步
// 定时器  网络请求


// 中间件
// const logger = store  => next => action =>{
//     console.log("dispatch->",action);
//     let result = next(action); // 加载下一个中间件
//     console.log("next state->",store.getState());
//     return result;
// }

// const error = store => next => action => {
//     try{
//         next(action)
//     }catch(e){
//         console.log("error->",e);
//     }
// }

// 创建store仓库
// const store = createStore(rootReducer,{},applyMiddleware(logger,error));
const store = createStore(rootReducer,{},composeWithDevTools(applyMiddleware(logger,thunk)));
// store.subscribe(() => console.log("state:", store.getState()))

// const render = () => {
//     ReactDOM.render(
//         <App
//             onIncrement={() => store.dispatch({ type: "INCREMENT" })}
//             onDecrement={() => store.dispatch({ type: "DECREMENT" })}
//             value={store.getState()}
//         />,
//         document.getElementById('root'));

// }
// render();
// store.subscribe(render)




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

49.Redux Redux异步中间件redux-thunk

(Redux Redux异步中间件redux-thunk&)

Redux Redux异步中间件redux-thunk&

处理数据前经历中间件的处理,再去处理数据,增加一层防护

单一化写法

用户操作记录,next加载中间件,中间件要放在创建仓库store的上面,所有用户操作都会加载中间件

可以有多个中间件

Throw 抛出错误

常用的中间件系统都已经提供了

src\actions\counter.js

redux-thunk异步

import * as actions from "../constants"
// export function increment(num){
//     return{
//         type:actions.INCREMENT,
//         num
//     }
// }

export function increment(num){
    return dispatch => {
        setTimeout(() =>{
            dispatch({
                type:actions.INCREMENT,
                num
            })
        },1000)
    }
}


export function decrement(num){
    return{
        type:actions.DECREMENT,
        num
    }
}

src\reducers\users.js

reducer 等待loading状态

import { FETCH_USER_SUCCESS,FETCH_USER_REQUEST, FETCH_USER_FAILURE } from "../constants"

const initialState = {
    user:{},
    isFetching: false,
    error: null,
}

const user = ( state = initialState,action ) => {
    switch(action.type){
        case FETCH_USER_SUCCESS:
            return {
                isFetching: false,
                error: null,
                user: action.user
            };
        case FETCH_USER_REQUEST:
            return {
                isFetching: true,
                error: null,
                user: {}
            }
        case FETCH_USER_FAILURE:
            return {
                isFetching: false,
                error: action.error,
                user: {}
            };
        default:
            return state;
    }
}

export default user

src\actions\users.js

thunk网络异步请求,dispatch触发传递数据

import { FETCH_USER_SUCCESS,FETCH_USER_FAILURE,FETCH_USER_REQUEST } from "../constants"

export const fetch_user_failure = (error) => {
    return {
        type: FETCH_USER_FAILURE,
        error
    };
};

export const fetch_user = (user) => {
    return {
        type: FETCH_USER_SUCCESS,
        user
    }
};

export const fetch_user_request = () => {
    return {
        type: FETCH_USER_REQUEST
    }
};


export const get_user = () =>{
    return dispatch =>{
        dispatch(fetch_user_request())
        fetch("http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php")
        .then(res => res.json())
        .then(data =>{
            dispatch(fetch_user(data.chengpinDetails[0]))
        })
        .catch(error =>{
            dispatch(fetch_user_failure(error));
        })
    }
}

user.jsx

div的className调整

import React from "react"
import { connect } from "react-redux"
import { bindActionCreators } from "redux"
import * as userActions from "../actions/user"

class User extends React.Component{

    render(){

        const { error, isFetching, user } = this.props.user;

        let data;

        if (error) {
            data = error;
        } else if (isFetching) {
            data = "Loading...";
        } else {
            data = user.title;
        }

        return(
            <div className="continer text-center">
                <p className="text-center">{ data }</p>
                <p className="text-center">User</p>
                <button className="btn btn-primary" onClick={ () => { this.props.userActions.get_user() } }>getUser</button>
            </div>
        )
    }
}

const mapStateToProps = (state) =>{
    return{
        user:state.user
    }
}

const mapDispatchToProps = (dispatch) =>{
    return {
        userActions:bindActionCreators(userActions,dispatch)
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(User)

50.Redux Redux-thunk网络请求

(Redux Redux-thunk网络请求&)

Redux Redux-thunk网络请求&

Thunk主要用于处理异步,异步操作有定时器和网络请求

希望延时1s增加值,无论是触发action,都是同一个action,把异步写在aciton中。

Dispatch触发事件。

需要处理异步

引入异步中间件

网络异步请求

修改reducers,修改state的初始,提取出来。State的操作不能直接改变state,success的时候return {}对象从action中读取user对象。

State是只读的,要改变需要返回一个新的state

修改action,单独进行异步操作return dispatch在回调中进行异步操作。

把数据给fetch_user里面,通过dispatch触发。Get_USER前台可以直接调用

通过connect关联redux,最后没有分号,可以读取数据

数据来源于user中的title,通过点击按钮读取数据,通过动作方法来读取数据。

点击user数据发生变化。

51.Redux Redux-thunk请求三种状态

(Redux Redux-thunk请求三种状态&)

Redux Redux-thunk请求三种状态&

网络请求延时,加载等待的过程,调整慢,isFetching等待状态

Actions也对应有三种等待状态

视图中响应,三种状态都赋值给data,只用加载data即可

视图中loading的状态,检查debugger返回是否为true

调用等待

异步都需要dispatch触发,否则无法传递数据

user.js

import { FETCH_USER_SUCCESS,FETCH_USER_REQUEST, FETCH_USER_FAILURE } from "../constants"

const initialState = {
    user:{},
    isFetching: false,
    error: null,
}

const user = ( state = initialState,action ) => {
    switch(action.type){
        case FETCH_USER_SUCCESS:
            return {
                isFetching: false,
                error: null,
                user: action.user
            };
        case FETCH_USER_REQUEST:
            return {
                isFetching: true,
                error: null,
                user: {}
            }
        case FETCH_USER_FAILURE:
            return {
                isFetching: false,
                error: action.error,
                user: {}
            };
        default:
            return state;
    }
}

export default user

src\actions\user.js

import { FETCH_USER_SUCCESS,FETCH_USER_FAILURE,FETCH_USER_REQUEST } from "../constants"

export const fetch_user_failure = (error) => {
    return {
        type: FETCH_USER_FAILURE,
        error
    };
};

export const fetch_user = (user) => {
    return {
        type: FETCH_USER_SUCCESS,
        user
    }
};

export const fetch_user_request = () => {
    return {
        type: FETCH_USER_REQUEST
    }
};


export const get_user = () =>{
    return dispatch =>{
        dispatch(fetch_user_request())
        fetch("http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php")
        .then(res => res.json())
        .then(data =>{
            dispatch(fetch_user(data.chengpinDetails[0]))
        })
        .catch(error =>{
            dispatch(fetch_user_failure(error));
        })
    }
}
// counter
export const INCREMENT = "INCREMENT"
export const DECREMENT = "DECREMENT"

// user
export const FETCH_USER_SUCCESS = "FETCH_USER_SUCCESS"
export const FETCH_USER_REQUEST = "FETCH_USER_REQUEST";
export const FETCH_USER_FAILURE = "FETCH_USER_FAILURE";

52.Redux Redux调试工具

(Redux Redux调试工具&)

Redux Redux调试工具&

检测redux数据的变化,在Chrome中应用安装即可

通过依赖来启动插件

引用到主入口文件,包裹整个插件

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { createStore,applyMiddleware } from "redux"
import { composeWithDevTools } from 'redux-devtools-extension';
import logger from "redux-logger"
import thunk from "redux-thunk"
// import reducer from "./reducers/counter"
import { Provider } from "react-redux"
import rootReducer from "./reducers"

// 异步和同步
// 定时器  网络请求


// 中间件
// const logger = store  => next => action =>{
//     console.log("dispatch->",action);
//     let result = next(action); // 加载下一个中间件
//     console.log("next state->",store.getState());
//     return result;
// }

// const error = store => next => action => {
//     try{
//         next(action)
//     }catch(e){
//         console.log("error->",e);
//     }
// }

// 创建store仓库
// const store = createStore(rootReducer,{},applyMiddleware(logger,error));
const store = createStore(rootReducer,{},composeWithDevTools(applyMiddleware(logger,thunk)));
// store.subscribe(() => console.log("state:", store.getState()))

// const render = () => {
//     ReactDOM.render(
//         <App
//             onIncrement={() => store.dispatch({ type: "INCREMENT" })}
//             onDecrement={() => store.dispatch({ type: "DECREMENT" })}
//             value={store.getState()}
//         />,
//         document.getElementById('root'));

// }
// render();
// store.subscribe(render)




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

(React 进阶&)

React 进阶&

1.React 进阶 组件优化1

(组件优化1&)

组件优化1&

parent.jsx

外部需要拿到count的值通过回调函数

回调函数获取定时器中的值,定时器网络请求组件销毁处理

state变化render重新渲染pureComponent

import React from "react"
import Child from "./child"
import Child1 from "./child1"


/**
 * 计数例子
 *  
 *  定时器
 *  网络请求
 *  事件监听
 *    在组件被销毁前都应得到相应的处理
 * 
 */

const MyAPI = {
    count:0,
    subscribe(cb){
        this.intervalId = setInterval(() =>{
            this.count += 1
            cb(this.count);
        },1000)
    },
    unSubscribe(){
        clearInterval(this.intervalId);
        this.reset();
    },
    reset(){
        this.count = 0;
    }
}

export default class Parent extends React.Component {

    state = {
        count:0
    }

    componentDidMount(){
        MyAPI.subscribe((currentCount) =>{
            this.setState({
                count:currentCount
            })
        })
    }

    componentWillUnmount(){
        MyAPI.unSubscribe();
    }

    render() {
        console.log("parent -> render");
        return (
            <div>
                Parent:{ this.state.count }
                <Child num={ this.state.count }/>
                <Child1 num={ 1 }/>
            </div>
        )
    }
}

child1.jsx 不通过生命周期方式进行处理

import React from 'react';


/**
 * Component:不会对数据进行比较
 * PureComponent:对数据进行浅比较 props
 * 
 */
export default class Child1 extends React.PureComponent {

    render() {
        console.log("child1 -> render");
        return (
            <div>
                Child1:{ this.props.num }
            </div>
        );
    }
}

child.jsx state发生改变render重新渲染,整个Child重新渲染,通过生命周期Child不用渲染

shouldComponentUpdate

import React from 'react';

export default class Child extends React.Component {

    /**
     * 
     * @param {*} nextProps 
     * @param {*} nextState 
     * 
     * 关于渲染问题
     */
    shouldComponentUpdate(nextProps,nextState){
        if(nextProps.num === this.props.num){
            return false;
        }
        return true;
    }

    render() {
        console.log("child -> render");
        return (
            <div>
                Child:{ this.props.num }
            </div>
        );
    }
}

App.js

HashRouter

import React from 'react';
import Demo1 from "./components/Demo1/parent"
import Home from "./components/Home"
import { HashRouter, Route, Switch } from "react-router-dom"

function App() {
    return (
        <HashRouter>
            <Switch>
                <Route exact path="/" component={ Home }></Route>
                <Route path="/demo1" component={ Demo1 }></Route>
            </Switch>
        </HashRouter>
    );
}

export default App;

Home.jsx

import React from 'react';
import Demo2 from "./Demo2"
import Demo3 from "./Demo3"
import Demo4 from "./Demo4"

import Banner from "./Demo5/banner"
import Chengpin from "./Demo5/chengpin"

import NewBanner from "./Demo5/New/NewBanner"
import NewChengpin from "./Demo5/New/NewChengpin"

import Demo6 from "./Demo6/Parent"

function Home() {
    return (
        <div>
            <Demo2 />
            <Demo3 />
            <Demo4 />

            <Banner />
            <Chengpin />

            <NewBanner />
            <NewChengpin />

            <Demo6 />
        </div>
    );
}

export default Home;

2.React 进阶 组件优化2

(组件优化2&)

组件优化2&

index.jsx,列表数据动态生成

Fragment返回li

import React,{ Fragment } from "react"

class Item extends React.Component {
    render() {
        return (
            <Fragment>
                <li>Demo2 Item1</li>
                <li>Demo2 Item1</li>
            </Fragment>
        )
    }
}


export default class Demo2 extends React.Component {
    render() {
        return (
            <ul>
                <Item />
            </ul>
        )
    }
}

3.React 进阶 组件优化3

(组件优化3&)

组件优化3&

index.jsx color只有在comment中使用,context上下文对象,getChildContext系统提供方法,context对象直接传递history不用两次传递

context孙子组件通信传递history

import React from "react"
import PropTypes from "prop-types"

const Topic = (props) =>{
    return(
        <div>
            <Comment/>
        </div>
    )
}

/**
 * 
 * 路由:this.props.history.push("/"):必须是路由直接子元素,如果是孙子元素,则不能使用
 * 
 * withRouter
 * 
 */

const Comment = (props,context) =>{
    return(
        <div>
            { context.color }
        </div>
    )
}

export default class Demo3 extends React.Component{

    getChildContext(){
        return{
            color:"red"
        }
    }

    render(){
        return(
            <div>
                <Topic/>
            </div>
        )
    }
}

Comment.contextTypes = {
    color:PropTypes.string
}
Demo3.childContextTypes = {
    color:PropTypes.string
}

4.React 进阶 Fragment

(React 进阶 Fragment&)

React 进阶 Fragment&

5.React 进阶 Context

(React 进阶 Context&)

React 进阶 Context&

6.React 进阶 高阶组件

(React 进阶 高阶组件&)

React 进阶 高阶组件&

index.jsx 可以在高阶组件中对MyData进行处理

高阶组件定义,

import React from "react"

/**
 * 
 * 高阶组件
 *  1.函数
 *  2.参数一个组件
 *  3.返回值也是一个组件
 */

const withFetch = (ComposeComponent) =>{
    return class extends React.Component{
        render(){
            return(
                <ComposeComponent {...this.props} />
            )
        }
    }
}

class MyData extends React.Component{
    render(){
        return(
            <div>
                MyData:{this.props.data}
            </div>
        )
    }
}

const WithFetch = withFetch(MyData);

export default class Demo4 extends React.Component{
    render(){
        return(
            <div>
                <WithFetch data={"Hello WithFetch"}/>
            </div>
        )
    }
}

7.React 进阶 高阶组件应用

(React 进阶 高阶组件应用&)

React 进阶 高阶组件应用&

banner组件与chengpin组件出了url不同其他都一样

相似组件通过高阶组件优化处理

banner.jsx

import React, { Component } from 'react';

class Banner extends Component {
  constructor() {
    super();
    this.state = {
      loading: true,
      banner: null
    };
  }

  componentDidMount() {
    fetch('http://iwenwiki.com/api/blueberrypai/getIndexBanner.php')
      .then(res => res.json())
      .then(banner => {
        this.setState({
          loading: false,
          banner: banner
        });
      })
  }

  render() {
    if(this.state.loading) {
      return (
        <div>loading</div>
      )
    } else {
      return (
        <h1>{this.state.banner.banner[0].title}</h1>
      )
    }
  }
}

export default Banner;

chengpin.jsx

import React, { Component } from 'react';

class Chengpin extends Component {
  constructor() {
    super();
    this.state = {
      loading: true,
      chengpin: null
    };
  }

  componentDidMount() {
    fetch('http://iwenwiki.com/api/blueberrypai/getChengpinInfo.php')
      .then(res => res.json())
      .then(chengpin => {
        this.setState({
          loading: false,
          chengpin: chengpin
        });
      })
  }

  render() {
    if(this.state.loading) {
      return (
        <div>loading</div>
      )
    } else {
      return (
        <h1>{this.state.chengpin.chengpinInfo[0].title}</h1>
      )
    }
  }
}

export default Chengpin;

withFetch.jsx return两个函数

import React,{Component} from 'react'

const withFetch = (url) => (View) => {
    return class extends Component {
        constructor() {
            super();
            this.state = {
                loading: true,
                data: null
            }
        }

        componentDidMount() {
            fetch(url)
                .then(res => res.json())
                .then(data => {
                    this.setState({
                        loading: false,
                        data: data
                    });
                })
        }

        render(){
            if(this.state.loading){
                return(
                    <div>loadding....</div>
                )
            }else{
                return <View data={ this.state.data }></View>
            }
        }

    }
}

export default withFetch

NewBanner.jsx,有两个参数第二个参数是组建视图,相同得到放到高阶组件处理

import React from "react"
import withFetch from "../withFetch"

const Banner = withFetch("http://iwenwiki.com/api/blueberrypai/getIndexBanner.php")(props =>{
    return(
        <div>
            <p>
                { props.data.banner[0].title }
            </p>
        </div>
    )
})

export default Banner;

NewChengpin.jsx

import React from "react"
import withFetch from "../withFetch"

const Chengpin = withFetch("http://iwenwiki.com/api/blueberrypai/getChengpinInfo.php")(props =>{
    return(
        <div>
            <p>
                { props.data.chengpinInfo[0].title }
            </p>
        </div>
    )
})

export default Chengpin;

8.React 进阶 错误边界处理

(React 进阶 错误边界处理&)

React 进阶 错误边界处理&

Parent.jsx

import React from 'react'
import Errors from "./Errors"
import ErrorBoundary from "./ErrorBoundary"

export default class Parent extends React.Component{

    state = {
        count:0
    }

    increment = () =>{
        this.setState({
            count:this.state.count+1
        })
    }


    decrement = () =>{
        this.setState({
            count:this.state.count-1
        })
    }


    render(){
        return(
            <div>
                <h3>这是一个标题</h3>
                <p>{ this.state.count }</p>
                <ErrorBoundary render={ (error,errorInfo) => <p>{ '加载时发生错误' }</p> }>
                    <Errors />
                </ErrorBoundary>
                <button onClick={ this.increment }>Increment</button>
                <button onClick={ this.decrement }>Decrement</button>
            </div>
        )
    }
}

Errors.jsx

错误边界componentDidCatch

import React from 'react'

export default class Errors extends React.Component{

    render(){
        return(
            <ul>
                {
                    null.map((element,index) =>{
                        return <li key={index} >{ element }</li>
                    })
                }
            </ul>
        )
    }

}

ErrorBoundary.jsx

import React from "react"

export default class ErrorBoundary extends React.Component{
    state = {
        hasError:false,
        error:null,
        errorInfo:null
    }

    /**
     * 子元素发生错误时触发
     */

    componentDidCatch(error,errorInfo){
        this.setState({
            hasError:true,
            error:error,
            errorInfo:errorInfo
        })
    }

    render(){
        if(this.state.hasError){
            return <div>{ this.props.render(this.state.error,this.state.errorInfo) }</div>
        }
        return this.props.children;
    }
}

(React&Redux实战-登录注册认证&)

React&Redux实战-登录注册认证&

(React 企业级实战项目-宜居&)

React 企业级实战项目-宜居&

 

 

 

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页