zoukankan      html  css  js  c++  java
  • 【温故知新】—— React/Redux/React-router4基础知识&独立团Demo

    前言:React专注View层,一切皆组件;全部使用ES6语法,最新版本为React16。

    Redux是专注于状态管理的库,和react解耦;单一状态,单向数据流。【独立团github地址


    一、React基础知识

        React基础语法

    • import React
    • class语法新建组件,render里直接使用
    • render函数返回值就是输出JSX语法,会把JSX转成js执行

        React的View层语法

    • JS里直接写html
    • Class里要写成className
    • 变量用{ }包裹即可

        React的Api

    • 一切都是组件
    • 类实现组件,使用JSX语法
    • 组件间通信通过属性props传递
    1. 使用<组件 数据='值' >的形式传递
    2. 组件里使用this.props获取值
    3. 如果组件只有render函数,还可以用函数的形式写组件
    • 组件内部通过state管理状态
    1. JSX本质就是js,所以直接数组.map渲染列表,【注意列表项必需有唯一key
    2. Constructor构造函数设置组件初始状态,记得执行super(props)
    3. State就是一个不可变的对象,使用this.state获取
    4. 通过this.setState修改,不能直接修改
    • onClick点击事件
    1. JSX里,onClick={this.函数名}来绑定事件
    2. this引用的问题,需要在构造函数里用bind绑定this,或者箭头函数直接绑定
    3. this.setState修改state,记得返回新的state,而不是修改

        React生命周期

    • 初始化周期
    • 组件重新渲染生命周期
    • 组件卸载声明周期

        独立团Demo

         

    import React from 'react';
    
    class App extends React.Component{
          render(){
             let boss = '李云龙'
             return (
                <div>
                   <h2>独立团,团长{boss}</h2>
                   <FirstYin leader='张大喵'></FirstYin>
                   <Squadron leader='孙德盛'></Squadron>
                </div>
             )
          }
    }
    
    function Squadron(props){
       return <h2>骑兵连连长{props.leader},冲啊!</h2>
    }
    
    class FirstYin extends React.Component{
       constructor(props) {
         super(props)
         this.state = {
           solders: ['虎子', '柱子', '王根生']
         }
         // this.addSolder = this.addSolder.bind(this)
       }
       componentWillMount(){
         console.log('组件马上就要加载了')
       }
       componentDidMount(){
        console.log('组件加载完成了')
       }
       addSolder = () => {
         console.log('hello add solder')
         this.setState({
           solders: [...this.state.solders, '新兵蛋子编号:'+Math.random()]
         })
       }
       render(){
          console.log('组件正在加载')
          return (
             <div>
                <h2>一营营长,{this.props.leader}</h2>
                <button onClick={this.addSolder}>新兵入伍</button>
                <ul>
                  {this.state.solders.map(solder => {
                      return <li key={solder}>{solder}</li>
                   })}
                </ul>
             </div>
          )
       }
    }
    
    export default App;  

    二、Redux基础知识

        Redux核心概念

    • Store:保存数据的容器,一个应用只能有一个Store。Redux提供createStore函数,创建Store
      import {createStore} from 'redux';
      const store = createStore(fun); //createStore的参数为reducer函数  
    • State:数据状态。Store在某一时刻的状态,可以通过store.getState()获取到。
      const state = store.getState(); 
    • Action:Redux改变state必需通过Action,实际上是一个JSON对象,该对象必须包含type属性,表示Action的名称。
      //该函数不需要主动去调用,事实上我们在store.dispatch的时候,会自动触发。
      const action = {
          type: 'ADD',   //action名称
          val: 5         //携带数据
      };    
    1. Action Creator:Action生成函数,用于创建Action,类似于工厂模式。若不使用,需要写很多Action。
      function createAdd(number) {
          return {
              type: 'ADD',
              val: number
          }
      }
      const action = createAdd(5);
    2. store.dispatch(action):View用于触发数据变化的唯一方式

      import {createStore} from 'redux';
      const store = createStore(fun);
       
      store.dispatch({   //state+5
          type: 'ADD',
          val: 5
      }); 
    • Reducer:Action改变数据状态需要遵守的规律函数
      const defaultState = 0;
      
      //这里的reducer不需要主动去调用,我们只需要向容器中丢一块砖头(store.dispatch(action)),它会自动触发该方法
      const reducer = (state = defaultState, action) => {
          switch (action.type) {
              case 'ADD':
                  return state + action.val;
              case 'DEC':
                  return state - action.val;
              default:
                  return state;
          }
      };

      注意:Reducer是一个纯函数,纯函数的要求之一是不能改写参数

      // 参数state和action是固定的
      function reducer(state, action) {
          let newSate = {}; 
          return { ...state, ...newSate}
      }
      
    • store.subscribe(listener):监听函数;会返回一个解除函数,调用该解除函数,就不再监听了
      import { createStore } from 'redux';
      const store = createStore(reducer);
       
      let unsubscribe = store.subscribe(listener);  //监听
       
      unsubscribe();  //解除监听
    • 官方Demo

      import { createStore } from 'redux';
       
      /**
       * 这是一个 reducer,形式为 (state, action) => state 的纯函数。
       * 描述了 action 如何把 state 转变成下一个 state。
       *
       * state 的形式取决于你,可以是基本类型、数组、对象、
       * 甚至是 Immutable.js 生成的数据结构。惟一的要点是
       * 当 state 变化时需要返回全新的对象,而不是修改传入的参数。
       *
       * 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper)
       * 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。
       */
      function reducer(state = 0, action) {
          switch (action.type) {
              case 'ADD':
                  return state + action.val;
              case 'DES':
                  return state - action.val;
              default:
                  return state;
          }
      }
       
      // 创建 Redux store 来存放应用的状态。
      // API 是 { subscribe, dispatch, getState }。
      let store = createStore(reducer);
       
      // 可以手动订阅更新,也可以事件绑定到视图层。
      store.subscribe(() =>
          console.log("听到状态变化了:" + store.getState())
      );
       
      // 改变内部 state 惟一方法是 dispatch 一个 action。
      // action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行
      store.dispatch({ type: 'ADD', val: 10 });
      // 10
      store.dispatch({ type: 'ADD', val: 20 });
      // 30
      store.dispatch({ type: 'DES', val: 30 });
      // 0  

        Redux单独使用 

           

    • src->index.js中:所有状态归redux管理(组件只负责view显示)
    1. reducer新建store,随时通过store.getState获取状态
      import {createStore} from 'redux'
      
      //通过reducer
      //根据老的 state和 action 生成新的state
      function counter(state=0, action){
          switch(action.type){
              case 'Add_GUN':
                return state+1
              case 'REMOVE_GUN':
                return state-1
              default:
                return 10
          }
      }
      //1、新建store
      const store = createStore(counter)
      
      const init = store.getState()
      console.log(init) //10
    2. 需求状态变更,store.dispatch(action)来修改状态
      //2、派发事件 传递action
      store.dispatch({type: 'Add_GUN'})
      store.dispatch({type: 'REMOVE_GUN'})  
    3. reducer函数接收state和action,返回新的state,可以用store.subscribe监听每次修改
      //定义事件方法
      function listener(){
          const current = store.getState();
          console.log(`现在有机枪${current}把`)
      }
      //3、监听事件
      store.subscribe(listener)
    • 安装redux
      yarn add redux --sav
      
    • 启动项目
      yarn start

        Redux和React一起用(手动连接)

          

    • Redux相关内容,移到单独的文件index.redux.js单独管理:reducer+action
      //action type
      const Add_GUN = '加机关枪'
      const REMOVE_GUN = '减机关枪'
      
      //reducer
      export function counter(state=0, action){
          switch(action.type){
              case Add_GUN:
                return state+1
              case REMOVE_GUN:
                return state-1
              default:
                return 10
          }
      }
      
      //action creator
      export function addGUN(){
          return {type: Add_GUN}
      }
      export function removeGUN(){
          return {type: REMOVE_GUN}
      }
    • App.js中:把store.dispatch方法传递给组件,内部可以调用修改状态
      import React from 'react';
      
      class App extends React.Component{
            render(){
               const store = this.props.store
               const num = store.getState()
               const addGUN = this.props.addGUN
               const removeGUN = this.props.removeGUN
               return (
                  <div>
                     <h3>现在有机枪{num}把</h3> 
                  </div>
               )
            }
      }
      
      export default App;
    • index.js中:Subscribe订阅render函数,每次修改都重新渲染
      import React from 'react';
      import ReactDOM from 'react-dom';
      import App from './App';
      import {createStore} from 'redux'
      import {counter, addGUN, removeGUN} from './index.redux'
      
      const store = createStore(counter)
      
      function render(){
          ReactDOM.render(<App store={store} addGUN={addGUN} removeGUN={removeGUN}/>, document.getElementById('root'));
      }
      render()
      
      store.subscribe(render)

        Redux处理异步

          

    • Redux默认只处理同步,异步任务需要react-thunk中间件
    1. 安装插件
      npm install redux-thunk --save  
    2. index.js中:使用applyMiddleware开启thunk中间件
      import {createStore, applyMiddleware} from 'redux'
      import thunk from 'redux-thunk'
      import {addGunAsync} from './index.redux'
      
      const store = createStore(counter, applyMiddleware(thunk)) 
    3. index.redux.js中:Action可以返回函数,使用dispatch提交action
      //(模拟)异步函数提交dispatch
      export function addGunAsync(){
          return dispatch => {
              setTimeout(() => {
                 dispatch(addGUN())
              }, 2000)
          }
      }
    4. App.js中:把store.dispatch方法传递给组件,内部可以调用修改状态

      import React from 'react';
      
      class App extends React.Component{
            render(){
               const store = this.props.store
               const num = store.getState()
               const addGunAsync = this.props.addGunAsync
               return (
                  <div>
                     <h3>现在有机枪{num}把</h3> 
                     <button onClick={() => store.dispatch(addGunAsync())}>拖两天再给</button>
                  </div>
               )
            }
      }

        Redux调试工具

          

    • 火狐搜索redux安装
    • 项目本地安装
      npm install redux-devtools-extension --save  
    1. 新建store的时候判断window.decToolsExtension
    2. 使用compose组合函数结合thunk和window.devToolsExtension
      import {createStore, applyMiddleware, compose} from 'redux'
      
      const store = createStore(counter, compose(
            applyMiddleware(thunk),
            window.devToolsExtension ? window.devToolsExtension() : f => f
      ))
    3. 调试窗的redux选项卡,实时看到state

        使用React-redux优雅的链接react和redux

          

    • 安装react-redux
      npm install react-redux --save
      
    • 忘记subscribe,记住reducer,action和dispatch即可

    • React-redux提供Providerconnect两个接口来链接

    1. index.js中:Provider组件在应用最外层,传入store即可,只用一次

      import {Provider} from 'react-redux'
      import {counter} from './index.redux'
      
      ReactDOM.render(
          <Provider store={store}>
              <App />
          </Provider>,
          document.getElementById('root')
      ); 
    2. Connect负责从外部获取组件需要的参数(mapStateToProps, actionCreators

      import React from 'react';
      import {connect} from 'react-redux'
      import {addGUN, removeGUN, addGunAsync } from './index.redux'
      
      class App extends React.Component{
            render(){
                return (
                  <div>
                     <h3>现在有机枪{this.props.num}把</h3> 
                     <button onClick={this.props.addGUN}>申请武器</button>
                     <button onClick={this.props.removeGUN}>上交武器</button>
                     <button onClick={this.props.addGunAsync}>拖两天再给</button>
                  </div>
               )
            }
      }
      
      const mapStateToProps = (state) => {
         return {
            num: state
         }
      }
      const actionCreators = {addGUN, removeGUN, addGunAsync}
      
      App = connect(mapStateToProps, actionCreators)(App) 
      export default App;  
    • Connect可以用装饰器的方式来优化

    1. 弹出个性化配置

      npm run eject
    2. 安转专门支持装饰器的插件

      npm install babel-plugin-transform-decorators-legacy --save-dev
    3. Package.json里babel加上plugins配置

      "plugins": [
          ["@babel/plugin-proposal-decorators", { "legacy": true }],
      ]  
    4. 优化connect

      import React from 'react';
      import {connect} from 'react-redux'
      import {addGUN, removeGUN, addGunAsync } from './index.redux'
      
      
      @connect(
          state => ({num: state})
         {addGUN, removeGUN, addGunAsync}
      )  //使用装饰器方法优化connect
      
      class App extends React.Component{
            render(){
                return (
                  <div>
                     <h3>现在有机枪{this.props.num}把</h3> 
                     <button onClick={this.props.addGUN}>申请武器</button>
                     <button onClick={this.props.removeGUN}>上交武器</button>
                     <button onClick={this.props.addGunAsync}>拖两天再给</button>
                  </div>
               )
            }
      }
      
      export default App;  
      

    三、React-router4基础知识 

        React-router4

    • React官方推荐路由库,4是最新版本,和之前版本不兼容,浏览器和RN均兼容
    • React开发单页应用必备,践行路由即组件的概念
    • 核心概念:动态路由、Route、Link、Switch
    • Web中应用React-router:安装react-router-dom作为前端路由
      npm install react-router-dom --save
      
    • 入门组件

    1. BrowserRouter包裹整个应用

    2. Router路由对应渲染的组件,可嵌套

    3. Link跳转专用

      import React from 'react';
      import ReactDOM from 'react-dom';
      import {BrowserRouter, Route, Link} from 'react-router-dom'
      
      function Yiying(){
          return <h2>一营</h2>
      }
      
      function Erying(){
          return <h2>二营</h2>
      }
      
      function Qibinglian(){
          return <h2>骑兵连</h2>
      }
      
      ReactDOM.render(
          <Provider store={store}>
              <BrowserRouter>
                  <div>
                      <ul>
                          <li>
                              <Link to='/'>一营</Link>  //点击跳到指定路由
                          </li>
                      </ul>
                      <ul>
                          <li>
                              <Link to='/erying'>二营</Link>
                          </li>
                      </ul>
                      <ul>
                          <li>
                              <Link to='/qibinglian'>骑兵连</Link>
                          </li>
                      </ul>
                      <Route path='/' exact component={Yiying}></Route>  //exact表明路由完全匹配
                      <Route path='/erying' component={Erying}></Route>
                      <Route path='/qibinglian' component={Qibinglian}></Route> //路由对应渲染模板
                  </div>
              </BrowserRouter>
          </Provider>,
          document.getElementById('root')
      );  
    • 其它组件
    1. url参数,Route组件参数可用冒号标识参数
      <Route path='/:location' component={Test}></Route> 
    2. Redirect组件  跳转
      <Redirect to='/qibinglian'></Redirect>  
    3. Switch只渲染命中的第一个子Route组件
      <Switch>
             <Route path='/' exact component={Yiying}></Route>
             <Route path='/erying' component={Erying}></Route>
             <Route path='/qibinglian' component={Qibinglian}></Route>
      </Switch> 
      

        和Redux配合

    • 复杂redux应用,多个reducer,用combineReducers合并
    1. index.js中:引入合并后的reducer,并注入createStore中
      import reducers from './reducer'  //合并后的reducer
      
      const store = createStore(reducers, compose(
            applyMiddleware(thunk),
            window.devToolsExtension ? window.devToolsExtension() : f => f
      ))
    2. reducers.js中:合并所有reducer,并返回

      /**
       * 合并所有reducer 并且返回
       */
      import {combineReducers} from 'redux'
      import {counter} from './index.redux'
      import {auth} from './Auth.redux'
      
      export default combineReducers({counter, auth})   
    • Redirect组件 跳转
      return this.props.isAuth ? app : <Redirect to='/login'></Redirect>  
    • Switch只渲染一个子Route组件
      ReactDOM.render(
          <Provider store={store}>
              <BrowserRouter>
                  <Switch>
                      <Route path='/login' component={Auth}></Route>
                      <Route path='/dashboard' component={Dashboard}></Route>
                      <Redirect to='/dashboard'></Redirect>
                  </Switch> 
              </BrowserRouter>
          </Provider>,
          document.getElementById('root')
      );  
      

        


    注:转载请注明出处

  • 相关阅读:
    SecureCRT + Tmux 分屏 高效开发
    Python—基础之杂货铺
    Python—五大基本语句
    Python—运算符的类型
    Python—基本数据类型
    Python—变量详解
    Python—虚拟环境的创建与管理(virtualenv与virtualenvwrapper)
    Mysql—数据库管理与表管理
    Linux—服务器SSL/TLS快速检测工具(TLSSLed)
    Linux—yum使用详解
  • 原文地址:https://www.cnblogs.com/ljq66/p/10258242.html
Copyright © 2011-2022 走看看