美文网首页
React全家桶01

React全家桶01

作者: LM林慕 | 来源:发表于2019-10-31 22:50 被阅读0次

    此文项目代码:https://github.com/bei-yang/I-want-to-be-an-architect
    码字不易,辛苦点个star,感谢!

    引言


    此篇文章主要涉及以下内容:

    1. redux
    2. redux中间件
    3. react-router4

    学习资源


    起步


    redux上手


    安装

    npm i redux --save
    

    redux中首先我们要了解的就是store,这就是帮咱们管理数据的政委,具有全局唯一性,所有的数据都在这一个数据源里进行管理,但是本身reduxreact并没有直接的联系,可以单独试用,复杂的项目才需要redux来管理数据,简单项目state+props+context足矣。
    redux之所以难上手,是因为上来就有太多的概念需要学习,用一个累加器举例:

    1. 需要一个store来存储数据
    2. store里的state是放置数据的地方
    3. 通过dispatch一个action来提交对数据的修改
    4. 请求提交到reducer函数里,根据传入的actionstate,返回新的state

    有点绕,贴代码

    使用

    store.js

    import { createStore } from 'redux'
    
    const counterReducer = (state = 0, action) => {
      switch (action.type) {
        case 'add':
          return state + 1
        case 'minus':
          return state - 1
        default:
          return state
      }
    }
    
    const store = createStore(counterReducer)
    
    export default store
    

    应用

    app.js

    import React from 'react'
    import store from './store'
    class App extends React.Component{
      render(){
        return <div>
          <p>{store.getState()}</p>
          <div>
            <button onClick={()=>store.dispatch({type:"add"})}>+</button>
            <button onClick={()=>store.dispatch({type:"minus"})}>-</button>
          </div>
        </div>
     }
    }
    export default App
    

    订阅

    index.js

    import React from 'react'
    import ReactDom from 'react-dom'
    import App from './App'
    import store from './store'
    const render = ()=>{
     ReactDom.render(
      <App/>,
      document.querySelector('#root')
    )
    }
    render()
    store.subscribe(render)
    

    react-redux


    react整合redux,简化使用难度,需要react-redux的支持
    提供了两个api

    1. provider顶级组件,提供数据
    2. connect高阶组件,提供数据和方法

    安装

    npm i react-redux --save
    

    注入store

    index.js

    import React from 'react'
    import ReactDom from 'react-dom'
    import App from './App'
    import store from './store'
    
    import { Provider } from 'react-redux'
    
    ReactDom.render(
      // 内部是使用的上下文进行的传值
      <Provider store={store}>
        <App />
      </Provider>,
      document.querySelector('#root')
    )
    

    使用状态

    app.js

    import React from 'react'
    import { connect } from 'react-redux'
    const mapStateToProps = state => {
      return {
        num: state
      }
    }
    const mapDispatchToProps = dispatch => {
      return {
        add: () => dispatch({ type: 'add' }),
        minus: () => dispatch({ type: 'minus' })
      }
    }
    class App extends React.Component {
      render() {
        return (
          <div>
            <p>{this.props.num}</p>
            <div>
              <button onClick={() => this.props.add()}>+</button>
              <button onClick={() => this.props.minus()}>-</button>
            </div>
          </div>
        )
      }
    }
    
    export default connect(
      mapStateToProps,
      mapDispatchToProps
    )(App)
    

    装饰器写法

    import React from 'react'
    import { connect } from 'react-redux'
    
    @connect(
      state => ({ num: state }),
      dispatch => ({
        add: () => dispatch({ type: 'add' }),
        minus: () => dispatch({ type: 'minus' })
      })
    )
    class App extends React.Component {
      render() {
        return (
          <div>
            <p>{this.props.num}</p>
            <div>
              <button onClick={() => this.props.add()}>+</button>
              <button onClick={() => this.props.minus()}>-</button>
            </div>
          </div>
        )
      }
    }
    
    export default App
    

    异步

    redux默认只支持同步,实现异步任务比如延迟,网络请求,需要中间件的支持,比如我们试用最简单的redux-thunkredux-logger

    npm i redux-thunk --save
    

    1. Reducer:纯函数,只承担计算State的功能,不适合承担其他功能,也承担不了,因为理论上,纯函数不能进行读写操作。
    2. View:与state一一对应,可以看作state的视觉层,也不合适承担其他功能。
    3. Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作。
    4. 实际的reduceraction store都需要独立拆分文件。

    试用redux-logger

    store.js

    import {applyMiddleware,createStore} from 'redux'
    import logger from 'redux-logger'
    
    const counterReducer = (state=0,action)=>{...}
    const store=createStore(counterReducer,applyMiddleware(logger));
    
    export default store
    

    试用redux-thunk

    import {applyMiddleware,createStore} from 'redux'
    import logger from 'redux-logger'
    import thunk from 'redux-thunk'
    
    const counterReducer = (state=0,action)=>{...}
    const store=createStore(counterReducer,applyMiddleware(logger,thunk));
    
    export default store
    

    应用

    App.js

    import React from 'react'
    import { connect } from 'react-redux'
    @connect(
      state => ({ num: state }),
      {
        add: () => ({ type: 'add' }),
        minus: () => ({ type: 'minus' }),
        asyncAdd: () => dispatch => {
          setTimeout(() => {
            // 实际的异步不在这里写
            // 异步结束后,手动执行dispatch
            dispatch({ type: 'add' })
          }, 1000)
        }
      }
    )
    class App extends React.Component {
      render() {
        return (
          <div>
               <p>{this.props.num}</p>
            <div>
                  <button onClick={() => this.props.add()}>+</button>
                  <button onClick={() => this.props.minus()}>-</button>
                  <button onClick={() => this.props.asyncAdd()}>延迟添加</button>
            </div>
          </div>
        )
      }
    }
    export default App
    

    代码需重构:抽离reducer和action,详情看代码中的store文件夹

    react-router-4


    安装

    npm i --save react-router-dom
    

    应用路由

    index.js

    import React from 'react'
    import ReactDom from 'react-dom'
    import { Provider } from 'react-redux'
    
    import { applyMiddleware, createStore } from 'redux'
    import logger from 'redux-logger'
    import thunk from 'redux-thunk'
    import { counterReducer } from './counter.redux'
    import App from './App'
    
    import { BrowserRouter } from 'react-router-dom'
    
    const store = createStore(counterReducer, applyMiddleware(logger, thunk))
    
    ReactDom.render(
      <BrowserRouter>
        <Provider store={store}>
          <App />
        </Provider>
      </BrowserRouter>,
      document.querySelector('#root')
    )
    

    配置、导航

    app.js

    import React from 'react'
    import { connect } from 'react-redux'
    import { add, minus, asyncAdd } from './counter.redux'
    import { Route, Link } from 'react-router-dom'
    function About() {
      return <div>About</div>
    }
    function Detail() {
      return <div>Detail</div>
    }
    @connect(
      state => ({ num: state }),
      { add, minus, asyncAdd }
    )
    class Counter extends React.Component {
      render() {
        return (
          <div>
               <p>{this.props.num}</p>
            <div>
                  <button onClick={() => this.props.add()}>+</button>
                  <button onClick={() => this.props.minus()}>-</button>
                  <button onClick={() => this.props.asyncAdd()}>延迟添加</button>
            </div>
          </div>
        )
      }
    }
    class App extends React.Component {
      render() {
        return (
          <div>
            <ul>
              <Link to="/">累加器</Link> 
              <Link to="/about">About</Link> 
              <Link to="/detail">Detail</Link>
            </ul>
            <div>
              <Route exact path="/" component={Counter} />
              <Route path="/about" component={About} />
              <Route path="/detail" component={Detail} />
            </div>
          </div>
        )
      }
    }
    export default App
    

    动态路由

    使用:id的形式定义参数

    <Route path="/detail/:id" component={Detail} />
    function Detail(props){
     return <div>Detail :{props.match.params.id}</div>
    }
    

    路由守卫

    // 路由守卫
    // 希望用法:<PrivateRoute component={About} path="/about" ...>
    const PrivateRoute = connect(state => ({ isLogin: state.user.isLogin }))(
      ({ component: Comp, isLogin, ...rest }) => {
        // 做认证
        // render:根据条件动态渲染组件
        return (
          <Route
            {...rest}
            render={props =>
              isLogin ? (
                <Comp />
              ) : (
                <Redirect
                  to={{
                    pathname: "/login",
                    state: { redirect: props.location.pathname }
                  }}
                />
              )
            }
          />
        );
      }
    );
    

    重点看RouteSample.js文件

    你的赞是我前进的动力

    求赞,求评论,求分享...

    相关文章

      网友评论

          本文标题:React全家桶01

          本文链接:https://www.haomeiwen.com/subject/pnpnvctx.html