纵有疾风起
人生不言弃

React简书开发实战课程笔记——2

一、使用 react-transition-group 扩展,实现css动画
  • 官网网址:React Transition Group

  • 安装: npm install react-transition-group --save

    1.使用CSSTransition控制单个元素执行动画:

    import {  CSSTransition } from 'react-transition-group';
    
    <CSSTransition
      in={ this.state.xxx}  //this.state.xxx数据改变时执行动画
      timeout={ 1000}       //动画执行时间
      classNames='fade'    //类名前缀
      unmountOnExit        //加上这个属性,会在出场动画执行完毕时,移除这个DOM
      
      //钩子函数 //只写出一个作为举例
      onEntered={ (e) => {   //onEntered在入场动画执行完时执行(e代表被包裹的DOM元素,可以换成其他字符)
        e.style.color = 'blue';
      }}
      appear={ true}        //当页面第一次渲染时,执行一次入场动画(需要增加appear类)
    >
      <h1>Hello World</h1>
    </CSSTransition>
    

    需要写的css类如下:

    .fade-enter, .fade-appear { }                //入场动画刚开始 .fade-enter-active, .fade-appear-active { }  //入场动画执行过程 .fade-enter-done { }                         //入场动画执行完毕 .fade-exit { }                               //出场动画刚开始 .fade-exit-active { }                        //出场动画执行过程 .fade-exit-done { }                          //出场动画执行完毕
    

    其中.fade-appear类和.fade-appear-active类是上面appear={true}时才需要添加的。fade就是上面指定的类名前缀

    所有的钩子函数如下:

    onEnter     //入场动画刚开始时执行
    onEntering  //入场动画执行时执行
    onEntered   //入场动画执行完时执行
    
    onExit      //出场动画刚开始时执行
    onExiting   //出场动画执行时执行
    onExited    //出场动画执行完时执行
    

    2.配合TransitionGroup来实现操作多个DOM元素执行动画

    import {  TransitionGroup } from 'react-transition-group';
    
    <TransitionGroup>
    { 
      this.state.list.map((item, index) => { 
      return (
        <CSSTransition
          //这里CSSTransition就不需要in属性了,其他属性同上
        >
          <h1>{ item}</h1>
        </CSSTransition>
        );
      });
    }
    </TransitionGroup>
    
二、ant design框架初体验
  • ant design官网:Ant Design

  • 安装:npm install antd --save

  • 使用:

    import 'antd/dist/antd.css';
    
    //使用不同的UI组件,需要写上相应的导入语句
    //下面input框、button按钮作为举例:
    import {  Input, Button } from 'antd';
    
    <Input placeholder='antd input' />  //注意UI组件首字母大写
    <Button>add</Button>
    
三、redux
  • 安装:npm install redux --save

  • redux的数据流动关系如下图:
    React简书开发实战课程笔记——2插图

  • 打个比方来帮助理解redux的工作机制:store比作仓库,reducer比作一个笔记本,component比作仓库管理员,action比作这个仓库中数据变更的信息。首先,仓库中有一个笔记本,将仓库中杂乱无章的数据有条理的记录下来,每当数据改变时,都会有一个数据更新的信息,仓库管理员根据这个信息更新笔记本,并更新仓库中的数据,仓库中的数据被更新了,页面就会被重新渲染。

具体代码实现:

src目录下原有一个index.js项目入口文件文件,和一个Todolist.js组件文件

src目录下创建store文件夹,然后在store文件夹中创建两个文件:index.js、reducer.js

  • index.js (store目录下的):

    //这个文件的作用是“仓库”
    
    import {  createStore } from 'redux';
    import reducer from './reducer';  //笔记本
    
    const store = createStore(  //创建仓库
      reducer,  //将笔记本传递给仓库
      
      //在浏览器中使用redux插件
      window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
    );
    
    export default store;
    
  • reducer.js :

    //这个文件的作用是笔记本
    
    const defaultState = {   //将数据存放在这里
      inputValue: '',
      list: [
        'list1',
        'list2',
      ]
    };
    
    //笔记本会默认从仓库那里接受两个参数(state:数据,action:数据变更的信息)
    //state = defaultState:将笔记本中记录的数据与仓库中的数据对应起来
    export default (state = defaultState, action) => { 
      return state;
    }
    
  • Todolist.js:

    //用一个input框作为举例
    import store from './store/index.js';
    
    <input onChange={ this.handleInputChange} />
    
    handleInputChange(e) { 
      const action = {                //定义这个数据变更的信息
        type: 'input_change_value',  //给这个信息起一个唯一的名字
        value: e.target.value        //变更的数据
      };
      store.dispatch(action);        //将这个数据变更的信息传递给store
      //dispatch是组件向store发送action的唯一方法
    }
    

    当组件向store传递action后,默认的reducer也会接收到这个action,下面这段代码可以证明:

    export default (state = defaultState, action) => { 
      console.log(action);
    
      return state;
    }
    

    控制台输出如下:
    React简书开发实战课程笔记——2插图1

    我在输入框中输入了一个空格handleInputChange方法被执行,action传递给了store,默认地reducer也接收到了这个action,所以reducer可以在控制台打印出这个action

既然笔记本接收到了数据变更的信息,那么笔记本记录的数据也要更新:

  • reducer.js:

    //const defaultState = { 
    // inputValue: '',
    // list: [
    // 'list1',
    // 'list2',
    // ]
    //};
    
    //export default (state = defaultState, action) => { 
      if (action.type === 'input_change_value') { 
        const newState = JSON.parse(JSON.stringify(state));  //对state深拷贝
        newState.inputValue = action.value;                  //更新newState中的inputValue数据
        return newState;                                     //将新的数据返回给仓库来更新仓库
      }
      //由于不能直接修改state,所以要拷贝一份后再做修改
    
    // return state;
    //}
    
  • Todolist.js:

    //constructor(props) { 
    // super(props);
      this.handleStoreChange = this.handleStoreChange.bind(this);
    
      //subscribe用来监听store,一旦store中存储的数据发生变化,就自动执行这个函数
      store.subscribe(this.handleStoreChange);
    //}
    
    handleStoreChange() { 
      //store.getState() 用来获取store中最新的数据
      this.setState(store.getState());  //用最新的数据来替换仓库中原有的数据
    }
    

    数据被更新了,那么页面自然也就被更新了

store提供的三种方法:

  • store.dispatch(); ———–组件向store传递action的唯一方法
  • store.subscribe(); ———-监听store中的数据,一旦数据变化,就执行这个函数
  • store.getState(); ————获取store中的最新的数据

实际项目中,需要将actiontype名提取出来,并将每个action封装,下面是如何提取type和封装action:

  • 提取type名:在store目录下新建一个名为actionTypes.js的文件

    actionTypes.js:

    export const CHANGE_INPUT_VALUE = 'change_input_value';
    export const CLICK_ADD_BUTTON = 'click_add_button';
    export const DELETE_LIST_ITEM = 'delete_list_item';
    
  • 封装每一个action:在store目录下新建一个名为actionCreators.js的文件

    actionCreators.js:

    import { 
      CHANGE_INPUT_VALUE,
      CLICK_ADD_BUTTON,
      DELETE_LIST_ITEM
    } from './actionTypes';
    
    export const getChangeInputValueAction = (value) => ({ 
      type: CHANGE_INPUT_VALUE,
      value
    });
    
    export const getClickAddButtonAction = () => ({ 
      type: CLICK_ADD_BUTTON
    });
    
    export const getDeleteItemListAction = (index) => ({ 
      type: DELETE_LIST_ITEM,
      index
    });
    
  • 使用封装后的action:

    Todolist.js:

    import { 
      getChangeInputValueAction,
      getClickAddButtonAction,
      getDeleteItemListAction
    } from './store/actionCreators';
    
    handleInputChange(e) { 
      const action = getChangeInputValueAction(e.target.value);
      store.dispatch(action);
    }
    handleBtnClick() { 
      const action = getClickAddButtonAction();
      store.dispatch(action);
    }
    handleDeleteClick(index) { 
      const action = getDeleteItemListAction(index);
      store.dispatch(action);
    }
    

到目前为止,src 目录下的文件结构如下:
React简书开发实战课程笔记——2插图2

有错误或不足欢迎指正~

待续…

未经允许不得转载:起风网 » React简书开发实战课程笔记——2
分享到: 生成海报

评论 抢沙发

评论前必须登录!

立即登录