生命周期函数、redux的使用(一)

在定义React组件的时候,render()函数返回的html必须只有一个根元素,要想这个根元素不显示并且不占据页面空间,可以从react中引进Fragment组件

生命周期函数、redux的使用(一)_第1张图片

 

JSX语法细节

在JSX里面写注释的方法:

多行注释:
{/*注释注释*/}

单行注释:
{
//注释注释
}

属性:dangerouslySetInnerHTML={{_html: item}}可以让内容item不转义,直接显示

属性class写成className属性for写成htmlFor

 

标签用于扩大输入框的范围,点击文字的时候,光标定位到input输入框

 

PropTypes与DefaultProps的应用

PropTypes接受组件传过来的参数时,对参数类型做校验

通过下面的语句引进PropTypes,通过脚手架create-react-app已经有prop-types包,所以可以直接引进

import PropTypes from 'prop-types';
class TabNav extends Component{
   //强制设置变量的类型
   static propTypes = {
      val: PropTypes.string。isRequired,
      activeIndex: PropTypes.number,
      //可以是数字也可以是字符串
      text: PropTypes.arrayOf(PropTypes.number,PropTypes.string)
   };
}

defaultProps即对组件接收的参数赋予默认值,如果父组件没有给子组件传递该参数的值,则子组件使用默认值

 

state、props与render()函数的关系

当state、props中的属性的值发生变化的时候,render()函数重新执行,即当数据一变,就会调用render()函数,重新渲染页面,从而改变页面,达到数据一变,页面就会变

子组件的render()调用时机:当子组件的props或者state属性发生变化时调用render()函数,或者父组件的render()调用时,子组件的render()会调用

 

虚拟DOM------就是一个JS对象,用来描述真实的DOM

在React中,虚拟DOM的操作不怎么耗性能,实际是操作真实的DOM比较耗性能,比较新旧虚拟DOM的差异(使用diff算法),找到差异的地方,直接更新变化的DOM

虚拟DOM的优点:

1)性能提升,真实DOM的比对变成虚拟DOM的比对

2)它使得跨端应用得以实现。React Native

虚拟 DOM中的diff:同层比较,在用列表表示的时候,key的值最好不用index,使得不变的元素的新旧key值一样,从而提升性能

setState(对象/异步func(prevState),func---当第一个异步函数操作完之后就执行该函数):异步函数是为了将多次间隔较短的虚拟DOM的变化,合并成一次虚拟DOM的变化,提高性能

 

JXS中的tag中的属性ref的值是一个函数,用于获取DOM,但在实际中不推荐使用该属性获取该元素,因为React中是数据驱动,不推荐直接操作DOM 

 

React中的生命周期函数---指在某一时刻会自动执行的函数

initialization---组件初始化

setup props and state

 mounting----组件挂载(只执行一次)

//执行顺序
//1、在组件即将被挂载到页面的时候执行
componentWillMount(){
  console.log(1)
}

//2、将JSX模板渲染成真实的DOM
render(){}

//3、在组件挂载到页面之后调用
componentDidMount(){}

updation---组件更新(数据发生变化,props   state)

//props发生变化的时候,即数据发生变化,导致组件的更新,触发下面的过程

//1、一个组件要从父组件接受参数,只要父组件的render函数重新被执行了,子组件的这个生命周期函数就会被执行----也就是说这个组件第一次存在于父组件不会执行,如果这个组件之前存在于父组件中,才会执行
componentWillReceiveProps(){}

//2、组件在更新之前,自动调用,返回boolean类型值,决定是否更新组件
shouldComponentUpdate(){
   return true
}

//3、
componentWillUpdate(){}


//4、
render(){}


//5、
componentDidUpdate(){}
//state中的属性发生变化的时候,触发下面的函数
//1、
shouldComponentUpdate(){}

//2、
componentWillUpdate(){}

//3、
render(){}

//4、
componentDidUpdate(){}

unmounting---组件卸载

//组件卸载之前执行
componentWillUnmount(){}

shouldComponentUpdate 是做什么的,(react 性能优化是哪个周期函数?)

shouldComponentUpdate 的返回值是boolean类型,用来判断是否需要调用 render 方法重新描绘 dom(返回true值)。

因为 dom 的描绘非常消耗性能,如果我们能在 shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,可以极大的提高性能

 

 

 

生命周期函数的使用场景

在定义组件的时候,一定要书写render()函数,因为React内置了除了render()函数之外的所有生命周期函数

1)ajax请求放在componentDidMount()中,该函数只执行一次

 

使用charles实现本地数据mock,使用axios方法

 

使用css的transition,animation实现简单动画,或者使用react第三方插件react-transition-group实现用js实现的动画

  false或者false->true发生一些动画*/}
     in={this.state.showValidationMessage}
      {/*动画执行的时间*/}
     timeout={300}
      {在.css文件中定义的类名的前缀,如fade-enter,fade-enter-active}
     classNames="fade"
     //当元素被隐藏的时候,DOM被移除
     unmountOnExit
     //退出时的函数
     onExited={() => {
         this.setState({
            showValidationButton: true,
         });
     }}
     //当页面刚开始的时候也使用样式
     appear={true}
  >

组件实现单个组件的动画

+ 实现多个组件的动画

生命周期函数、redux的使用(一)_第2张图片

 

 

React是一个简单的视图层框架

Redux = Reducer + Flux:是一个数据层框架,主要方法是createStore(redux)和store.dispatch(action),store.subscribe(event)

Flux是一个辅助React的数据层框架:存在的问题是可以有很多个store,造成数据存储存在依赖的问题

生命周期函数、redux的使用(一)_第3张图片

有了Redux之后,将组件的数据存储在Store里面,当组件的数据发生变化,Store里面的数据发生变化,然后接着改变其他组件的数据
生命周期函数、redux的使用(一)_第4张图片

 

Antd(用于快速构建后台界面用的,前端UI用的较少)或者、semantic-ui-react是用于构建React UI 的插件

 

首先在项目中安装redux,redux在chrom中的调试插件redux devtools

创建reducer

1)在src/store/reducer.js文件里面定义reducer(相当于一个记录本,里面定义state的默认值,然后必须返回一个函数)

const defaultState = {
  inputVal: '123',
  list: [1,2]
}

//state是整个store里面的数据
export default (state = defaultState, action) => {
  return state;
}

2)在src/store/index.js文件里面定义store

//该方法用于创建store对象
import { createStore } from 'redux';
//导进reducer(记录本)
import reducer from './reducer';
const store = createStore(reducer);

export default store;

3)component连接store

//在component中引进store
import store from './store/index.js'
class TodoList extends Component{
  constructor(props){
    super(props);
    //利用store提供的getState()方法拿到store中的state数据
    this.state = store.getState() ;
  }
}

4)在浏览器中安装调试redux的插件redux devtools,然后在组件中需要进行如下配置

在创建store的地方进行如下配置

//该方法用于创建store对象
import { createStore } from 'redux';
//导进reducer(记录本)
import reducer from './reducer';
const store = createStore(reducer,window.__REDUX_DEVTOOLS_EXTENSION__ && 
   window.__REDUX_DEVTOOLS_EXTENSION__()
);

export default store;

5)在React Component中定义action,并且将action分发给store对象

//在TodoList组件里面定义action
//在输入框中定义事件change


handleInputChange(e){
  //创建action
  //input(React Component)框告诉store要做的action(Action Creators)
  const action={
    type:'change_input_value',
    //可以将input的value传递过去
    value:e.target.value
  }
  //组件将action传给store对象
  store.dispatch(action);
}

6)store接收到action之后,自动将接收到的action和store中之前的数据传给reducer,这时候需要在reducer里面根据action做相应的处理,将处理完之后的newState返回给store 对象

const defaultState = {
  inputVal: '123',
  list: [1,2]
}

//state是整个store里面的数据
// reducer可以接收state,但不能直接修改state
export default (state = defaultState, action) => {
  //根据action做相应的处理
  if( action.type === 'change_input_value' ){
    //对数据作一个深拷贝
    const newState = JSON.parse(JSON.stringify(state))
    //对公共数据的修改
    newState.inputVal = action.value
    // 将数据返回给store对象
    return newState
  }
  return state;
}

7)store接收到reducer处理之后返回的newState。这时候需要用newState替换掉component中的state数据

利用store.subscribe(event)订阅一个事件event,event用于更新component中的state数据

//在component中引进store
import store from './store/index.js'
class TodoList extends Component{
  constructor(props){
    super(props);
    //利用store提供的getState()方法拿到store中的state数据
    this.state = store.getState() ;
    
    // 在组件中订阅store对象的事件,store中数据发生变化,就自动执行该函数
    this.handleStoreChange = this.handleStoreChange.bind(this)
    store.subscribe(this.handleStoreChange);
  }

  handleStoreChange(){
    // 当组件感知store中的数据发生变化的时候,从store中
    // 拿到newState,然后替换掉当前组件的state数据,达到
    this.setState(store.getState())
  }
}

8)component中的state数据更新了,现在需要点击按钮时,将新增的数据添加到数组里面,而现在所有的数据都放到了store对象里面,即点击按钮的时候,需要改变的是store对象中的数据

在组件上面定义事件,在事件里面定义action,并通过store.dispatch(action)传递给store对象

// 在Button组件上绑定事件


// 在组件上定义action,并且通过store.dispach(action)将action分发给store对象
handleBtnClick() {
  // action对象必须有type属性,
  // 剩余的要对应上在reducer中定义的属性名
  const action = {
    type: 'add_todo_item'
  }
  // 将action传递给store
  store.dispatch(action)
}

9)store对象接收到action,就自动触发reducer根据action做相应的处理,处理完后将newState返回给store对象

const defaultState = {
  inputVal: '123',
  list: [1,2]
}

//state是整个store里面的数据
// reducer可以接收state,但不能直接修改state
export default (state = defaultState, action) => {
  //根据action做相应的处理
  if( action.type === 'change_input_value' ){
    //对数据作一个深拷贝
    const newState = JSON.parse(JSON.stringify(state))
    //对公共数据的修改
    newState.inputVal = action.value
    // 将数据返回给store对象
    return newState
  }

  //根据action做相应的处理
  if( action.type === 'add_todo_item' ){
    //对数据作一个深拷贝
    const newState = JSON.parse(JSON.stringify(state))
    //对公共数据的修改
    newState.list.push(newState.inputVal)
    // 将数据清空
    newState.inputVal = ''
    // 将数据返回给store对象
    return newState
  }

  return state;
}

10)store对象接收到newState,由于之前在component中的constructor中已经订阅事件store.subscribe(this.handleStoreChange);通过handleStoreChange修改组件的state,所以已经达到点击按钮,向数组添加数据的目的

 

点击具体的item的时候将其删除掉

1)在组件上面绑定事件,并且向事件传递index参数

{item}

2)在事件里面定义action,通过store.dispatch(action),将动作传递给store对象

handleItemDel(index){
  const action={
    type:'delete_todo_item',
    index
  }
  store.dispatch(action)
}

3)此时store接收到action,并将store中的state和action一起传给reducer,reducer执行相应的action,返回newState给store对象,由于之前在component的constructor中通过store.subscribe(event),在event中通过store.getState()重新对component的state赋值,达到删除功能

const defaultState = {
  inputVal: '123',
  list: [1,2]
}

//state是整个store里面的数据
// reducer可以接收state,但不能直接修改state
export default (state = defaultState, action) => {
  //根据action做相应的处理
  if( action.type === 'change_input_value' ){
    //对数据作一个深拷贝
    const newState = JSON.parse(JSON.stringify(state))
    //对公共数据的修改
    newState.inputVal = action.value
    // 将数据返回给store对象
    return newState
  }

  //根据action做相应的处理
  if( action.type === 'add_todo_item' ){
    //对数据作一个深拷贝
    const newState = JSON.parse(JSON.stringify(state))
    //对公共数据的修改
    newState.list.push(newState.inputVal)
    // 将数据清空
    newState.inputVal = ''
    // 将数据返回给store对象
    return newState
  }

    //根据action做相应的处理
    if( action.type === 'delete_todo_item' ){
      //对数据作一个深拷贝
      const newState = JSON.parse(JSON.stringify(state))
      //删除对应下标的数据
      newState.list.splice(action.index,1)
      // 将数据清空
      newState.inputVal = ''
      // 将数据返回给store对象
      return newState
    }
  return state;
}

 

ActionTypes的拆分

解决的问题:当action.type拼写错误,但在浏览器没有报错也没有提示任何信息,为了解决这个问题将ActionTypes在一个文件夹里面定义成常量,然后输出。当书写错误的时候,浏览器会报错

1)在src/store下新建文件actionTypes.js,内容如下

const CHANGE_INPUT_VALUE = 'change_input_value',
      ADD_TODO_ITEM = 'add_todo_item',
      DELETE_TODO_ITEM = 'delete_todo_item'
export {
  CHANGE_INPUT_VALUE,
  ADD_TODO_ITEM,
  DELETE_TODO_ITEM
}

2)在组件里面引进该对象,然后将action里面的type换成上述文件定义成的常量变量

同时在reducer中将action.type也换成定义的常量变量

 

使用actionCreator统一创建action,便于管理,提高代码的可读性,便于自动化测试

1)在src/store下面创建文件actionCreators.js

import {CHANGE_INPUT_VALUE} from './actionTypes'

// actionCreator,返回一个action对象
const getInputChangeAction = (value) => {
  type: CHANGE_INPUT_VALUE,
  value
}

export { getInputChangeAction }


 

2)在组件引入action

import {getInputChangeAction} from './store/actionCreators.js'

3)在组件中使用action

//在TodoList组件里面定义action
//在输入框中定义事件change


handleInputChange(e){
  //创建action
  //input(React Component)框告诉store要做的action(Action Creators)
  const action = getInputChangeAction(e.target.value)
  //组件将action传给store对象
  store.dispatch(action);
}

redux的3个基本原则

1)store对象必须是唯一的,在src/store/index.js中定义

2)只有store能够改变自己的内容(reducer根据action进行相应操作后,将newState返回给store,store将自己的内容更新,所以不能在reducer里面直接修改state的内容)

3)reducer必须是纯函数(固定输入,固定输出,并且不会有任何副作用---例如不会修改传入参数的值)

 

redux的核心API

createStore(reducer)------创建store
store.dispatch(action)----组件向store传递action
store.subscribe(event)----向store订阅事件,只要store内容一变,就触发event
store.getState()----------拿到store里面的内容

 

UI组件(展示型组件)与容器型组件的拆分

UI组件负责页面的展示,数据通过容器型组件传过来,通过props拿到数据;在TodoListUI.js里面只有render()函数里面直接返回JSX;

容器性组件TodoList.js负责页面的逻辑

 

Redux中发送异步请求获取数据----

在componentDidMount()中发送ajax请求,拿到数据后给store传递action

 1)在项目中安装axios插件

2)在容器型组件中引进axios

3)在componentDidMount()中定义action,并将action传递给store

componentDidMount(){
  axios.get('/list.json').then((res)=>{
    const data = res.data
    // 创建action
    const action = initListAction(data)
    store.dispatch(action)
  }).catch(e){console.log(e)}
}

接着在reducer中根据action.type进行操作

 

 

发使用redux-thunk中间件实现ajax数据请求

--------为了将异步请求和复杂的逻辑抽取出来,将代码放到一个统一的文件,便于统一管理

redux-thunk中间件可以把异步请求和复杂的逻辑放到action里面处理

在项目中安装redux-thunk,根据官网例子书写代码   https://github.com/reduxjs/redux-thunk    链接

1、在创建store对象的index.js文件做如下修改:对redux-thunk进行配置
 

// 该方法用于创建store对象
// 引进方法 applyMiddleware,才能使用中间件
import { createStore,applyMiddleware,compose } from 'redux';
//导进reducer(记录本)
import reducer from './reducer';
import thunk from 'redux-thunk';

const composeEnhancers =  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;

const enhancer = composeEnhancers(
  applyMiddleware(thunk),
  // other store enhancers if any
);

// 在创建stor的时候,使用reducer构建初始的数据,
// 在创建store的时候会使用中间件redux-thunk
const store = createStore(
    reducer,
    enhancer
);

export default store;

2、对redux-thunk进行配置好后,可以将异步操作放到action里面进行操作

在src/store下面创建文件actionCreators.js中使用了中间件redux-thunk,那么创建的action可以返回函数,而不仅仅是返回一个对象,在返回的函数里面进行异步操作

import {CHANGE_INPUT_VALUE} from './actionTypes'
import axios from 'axios'

// actionCreator,返回一个action对象
const getInputChangeAction = (value) => {
  type: CHANGE_INPUT_VALUE,
  value
}

// 使用Redux-thunk中间件之后,创建的action可以返回一个函数,当store接受
// 到这个action时,action的函数会自动执行
const getTodoList = () =>{
    return (dispatch) => {
        // 异步请求拿到数据
        axios.get('/list.json').then((res)=>{
            const data = res.data;
            //改变store里面的数据
            const action = initListAction(data);
            dispatch(action)
        })
    }
}

export { getInputChangeAction, getTodoList }


3、在组件的componentDIdMount()中调用上述函数,从而得到action

import { getTodoList } from 'actionCreators.js'

componentDIdMount(){
    // action是一个函数
    const action = getTodoList();
    // 执行action函数
    store.dispatch(action)
}

 

redux中间件---处理异步事件

redux中间件指的是Action和Store之间的中间件

中间件指的是对dispatch方法的升级,使得该函数的参数除了是对象之外还可以是函数

可以用redux-thunk对dispatch升级

生命周期函数、redux的使用(一)_第5张图片

 

Redux-saga中间件-----处理异步代码,在redux-saga里面会将一些异步代码放到单独文件里面

用了Redux-saga中间件,除了在reducer中接收action,还可以在saga文件中接收action

1)将Redux-saga插件安装到项目里面,https://github.com/redux-saga/redux-saga  链接

2)在src/store下创建sagas.js文件,用于存放异步代码

// saga必须使用generator
import { takeEvery,put } from 'redux-saga/effects'
import {GET_INIT_LIST} from './actionTypes'
import {initListAction} from './actionCreators'
import axios from 'axios'

function* getInitList(){
    // 处理请求失败的结果
    try{
        const res = yield axios.get('/list.json')
        const data = res.data
        const action = initListAction(data)
        // 将action传递给store
        yield put(action)
    }catch(e){
        console.log('list.json网络请求失败')
    }

}

function* mySaga() {
    // 获取每一个 action
    yield takeEvery(GET_INIT_LIST, getInitList);
}

export default mySaga;

 

 

3)在创建store对象的文件里面进行如下配置,src/store/index.js

// 该方法用于创建store对象
// 引进方法 applyMiddleware,才能使用中间件
import { createStore,applyMiddleware,compose } from 'redux';
//导进reducer(记录本)
import reducer from './reducer';
//存放异步代码
import mySaga from  './sagas'
// 创建中间件的方法
import createSagaMiddleware from 'redux-saga';
// create the saga middleware
const sagaMiddleware = createSagaMiddleware();

const composeEnhancers =  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;

const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware));

// 在创建stor的时候,使用reducer构建初始的数据,
// 在创建store的时候会使用中间件redux-thunk
const store = createStore(
    reducer,
    enhancer
);
// then run the saga
sagaMiddleware.run( mySaga);
export default store;

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

4)在src/store/actionTypes.js中定义常量

export const GET_INIT_LIST = 'get_init_list'

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

5)在创建action的文件src/store/actionCreators.js里面创建action,这个action返回的是对象

import {GET_INIT_LIST} from './actionTypes.js'
export const getInitList = ()=>({type:GET_INIT_LIST})

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

6)在组件生命周期里面调用

componentDidMount(){
    const action = getInitList()
    store.dispatch(action)
}

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 

React-redux的使用

通过以下步骤创建了store,reducer,并且组件和store建立连接:

1)在项目中安装react-redux

2)在src/TodoList.js书写组件的内容,创建store,reducer对象之后,在component组件文件里面引进store对象之后,通过store.getState()拿到store的数据,从而让store和component 建立连接

import React,{Component} from 'react'
import store from './store'
class TodoList extends Component{
    constructor(props){
        super(props)
        // 获取store对象的数据初始化state
        this.state = store.getState()
    }
    render(){
        return (
            
  • dell
) } } export default TodoList

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

3)在src/index.js中引进组件

import React from 'react'
import ReactDOM from 'react-dom'
import TodoList from './TodoList'
ReactDOM.render(,document.getElementById('root'))

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

4)在src/store/reducer.js下创建reducer,该文件返回纯函数,以及定义初始化state的数据

const defaultState = {
    inputValue:'',
    list:[]
};
export default (state=defaultState,action) => {
    return state
}

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

5)所有的数据放在store里面,在src/store/index.js下创建store对象

import { createStore } from 'redux'
import reducer from './reducer'
const store = createStore(reducer)
export default store

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

 

在React中使用Redux:
1)在src/index.js文件中使用React-redux的组件这样使得组件Provider的子元素可以获取到store的内容

store与子component建立连接

import React from 'react'
import ReactDOM from 'react-dom'
import TodoList from './TodoList'
// 引进React-redux中的 组件
import {Provider} from 'react-redux'
import store from './store'
const App = (
    // Provider连接了store,那么Provider的所有子元素可以获取到store内容
    
        
    
)
ReactDOM.render(App,document.getElementById('root'))

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2)在子组件中通过connect()使store和子组件建立连接,并且将store中的state映射到props,同时通过props修改store中的内容

import React,{Component} from 'react'
import store from './store'
import {connect} from 'react-redux'
class TodoList extends Component{
    constructor(props){
        super(props)
        // 获取store对象的数据初始化state
        this.state = store.getState()
    }
    render(){
        return (
            
{/*这是因为将state映射成props*/}
  • dell
) } } // 就是将store里面的公用数据映射成props const mapStateToProps = (state)=>{ return { inputValue:state.inputValue } } // 通过props修改store的内容 // 让store.dispatch挂载到props上 const mapDispatchToProps = (dispatch) => { return { changeInputValue(e){ const action = { type:'change_input_value', value:e.target.value } // 修改store的内容 dispatch(action) }, handleClick(){ const action ={ type:'add_item' } } dispatch(action) } } // 让子组件TodoList和store建立连接 //通过mapStateToProps,store里面的state会映射成组件的props export default connect(mapStateToProps,mapDispatchToProps)(TodoList)

3)通过上面配置,将action通过dispatch到store,并传给reducer,在reducer中需要根据action.type进行相应处理

const defaultState = {
    inputValue:'',
    list:[]
};
export default (state=defaultState,action) => {
    if( action.type === 'change_input_value' ){
        const newState = JSON.parse(JSON.stringify(state))
        newState.inputValue = action.value
        return newState
    }
    if( action.type === 'add_item' ){
        const newState = JSON.parse(JSON.stringify(state))
        newState.list.push(newState.inputValue)
        newState.inputValue = ''
        return newState
    }
    return state
}

改进后的组件:

import React,{Component} from 'react'
import store from './store'
import {connect} from 'react-redux'

// UI组件,无状态组件---提升性能,无生命周期函数,只是进行展示,从props中拿数据
const TodoList = (props)=>{
    const { inputValue,changeInputValue, handleClick } = props
    return (
        
{/*这是因为将state映射成props*/}
    { this.props.list.map((item,index)=>{ return
  • {item}
  • }) }
) } // 就是将store里面的公用数据映射成props const mapStateToProps = (state)=>{ return { inputValue: state.inputValue, list: state.list } } // 通过props修改store的内容 // 让store.dispatch挂载到props上 const mapDispatchToProps = (dispatch) => { return { changeInputValue(e){ const action = { type:'change_input_value', value:e.target.value } // 修改store的内容 dispatch(action) }, handleClick(){ const action ={ type:'add_item' } dispatch(action) }, handleDelete(index){ const action ={ type:'delete_item', index } dispatch(action) } } } // 让子组件TodoList和store建立连接 //通过mapStateToProps,store里面的state会映射成组件的props // connect()输出的结果是容器组件,因为将数据和逻辑与UI组件进行结合就是容器组件 export default connect(mapStateToProps,mapDispatchToProps)(TodoList)

 

Styled-Components的使用----让组件的样式只对组件的样式生效,不会在全局中生效,在标签上直接书写css然后输出该组件

问题:在src目录下有文件index.js    index.css  App.js,在文件index.js引进index.css,但没有在App.js里面引进index.css,也可以使用在index.css里面的类--------在React中引进css,将会在全局中生效,就会造成组件中的类冲突

解决方法:使用第三方插件---styled-components

styled-components的定义

styled-components 是一个常用的 css in js 类库,和所有同类型的类库一样,通过 js 解决了原生 css 所不具备的能力,比如变量、循环、函数等

styled-components比其他css预处理器的优点

  • 诸如 sass&less 等预处理可以解决部分 css 的局限性,但还是要学习新的语法,而且需要对其编译,需要复杂的 webpack 配置
  • 如果有过sass&less的经验,也能很快的切换到styled-components,因为大部分语法都类似,比如嵌套,& 继承等, styled-componens 很好的解决了学习成本与开发环境问题,很适合 React 技术栈 && React Native 的项目开发

styled-components解决的问题

  • className 的写法会让原本写css的写法十分难以接受
  • 如果通过导入css的方式 会导致变量泄露成为全局 需要配置webpack让其模块化
  • 以及上面提到的解决了原生 css 所不具备的能力,能够加速项目的快速开发

转载出处:https://www.jianshu.com/p/2178abb2ee95  

 

1、在项目中安装styled-components,不需要在文件中引进,但是将.css文件改成.style.js文件

2、全局样式injectClobal被createGlobalStyle替代,用组件的方式渲染,具体使用

3、将css reset的代码复制到createGlobalStyle里面----让默认样式在所有浏览器表现一致

 

 

使用iconfont嵌入头部图标

官网  https://www.iconfont.cn/

1、登录iconfont,在“图标管理”下选择“我的项目”,点击右边“新建项目”的图标

2、在主页的搜索框中输入要查找的图标名,然后选择要的图表,选择“添加入库”

3、所有图表选择好之后,点击右上角的“购物车”图标,点击“添加至项目”

4、然后点击“下载至本地”

5、然后将压缩包解压缩,将文件iconfont.eot       iconfont.svg      iconfont .ttf       iconfont .woff文件复制到项目的src/static/iconfont文件夹下面

6、在项目中使用 iconfont,首先需要想修改文件iconfont.css里面的内容:将路径以iconfont开头的路径改成相对路径

@font-face {
  font-family: "iconfont";
  src: url('./iconfont.eot?t=1551963575525'); /* IE9 */
  src: url('./iconfont.eot?t=1551963575525#iefix') format('embedded-opentype'), /* IE6-IE8 */
  url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAPQAAsAAAAAB9gAAAOCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDHAqDFIJ7ATYCJAMQCwoABCAFhG0HRxvsBsgeh+kWI3+SnJzkPR6+v0/Pff9m3SxAmWAAMx7gZW3HK9aKFmtWXnaB/F9b+gfYhA51IebGpvWVYUUfO3VRUveT+E30FGkCBID6xL3Tpm2w+SzLaaxFa9P/3EVdgPHWwPbENmUFWiAJesvwapfCQR8mgLaBwqF1YXk98DhkVABxbzHpgM84cQ3kwEO8KhYmoCfQ4Mt85gGAx+D78Q+x8QCFpgIycXMsMEL2l//Xz+y0/9NgmEcB1XR+yMtABSyBBHGuDG6xUWaJhc3unESgiceAqdoSv37+/x/URzHy9C8PBBYDog6E2AVYQbYCX/5cSoCvRGWV6TMmKIAPsqAJtIEH4AVhzT0vMbiet7fQsz3P9xAmLrgTTBsNYw+eRK9ejatHWCtAWtMDsalBmy5lTVeTbr702TZRUl83bSO9eFH/8mXDwtdZDasXHtyovH6tTctLrvLqVScsta/HNmHwkDUD8abejbqLwkKAduAmvOARmq7VTg9eML3h1D6Y9iwsvI5QrF+J/x0SEZcfG5sflSgt8kd5w4b61gUs94mL81m+Y2fjlh7ZG1T1xJGK8u9HjnxnPuzILijgLJB0qqpq/EkqM//EifmujpFczPxkcirxr1bVdX3iBlxZxtiWLbOBnVkWFcHbQJNc9DQ4/ynp+F+f98qaWdXA5Ootma+55kwPvZkchTQ5ka4QydJhuFCWnfp5hJbe79OjuW/Ar4CB4Aa4nWTvsiWBsIWdygL/P9vkDPwnb3PfWkZ2Sv/HCxwAXvcmnsXh20kOhql+g6qz6n+pOpalpSGuTEPLlXYoRadGKUAbBv5SgbG3U5hnnYkEXo8EhbcBqPD8qckMR40gHnW8LLSFKVre0Y2ChbIdgIXZCEhnR8HoSAWrs4dUjvkGGj19g5fOscCk6LahIDALzlOIjhKjqB8vWgwup8w8FIfkWmIabdcpaU0gkIjiscTFmMjofL6IOIkyxRTPGFMspbIoKy6HWIiOI3a7S3QrLisx0Egzpe7UqCi56kGRBpcDsDwKQocijER644ksDFycZK86hQufr0WYjGanozSUNGUlhMLD0rkoRqToDtQio7NTya2c4jGGSSyKkolkChcHUSHyE3aacRG5q/tZEQZUJPOAlFuqKKgkdzVGLm92vOEaaCO9MhjEIg5pQLj2iR5Co2PikrCsc5qMOqvFSzM5OgAAAA==') format('woff2'),
  url('./iconfont.woff?t=1551963575525') format('woff'),
  url('./iconfont.ttf?t=1551963575525') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
  url('./iconfont.svg?t=1551963575525#iconfont') format('svg'); /* iOS 4.1- */
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

7、图标字体可能是用于全局的,所以当成全局样式来处理,将iconfont.css文件改成iconfont.js,并修改为样式组件,内容如下:

import { createGlobalStyle } from 'styled-components';

export const iconFontGlobal = createGlobalStyle `
  @font-face {
    font-family: "iconfont";
    src: url('./iconfont.eot?t=1551963575525'); /* IE9 */
    src: url('./iconfont.eot?t=1551963575525#iefix') format('embedded-opentype'), /* IE6-IE8 */
    url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAPQAAsAAAAAB9gAAAOCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDHAqDFIJ7ATYCJAMQCwoABCAFhG0HRxvsBsgeh+kWI3+SnJzkPR6+v0/Pff9m3SxAmWAAMx7gZW3HK9aKFmtWXnaB/F9b+gfYhA51IebGpvWVYUUfO3VRUveT+E30FGkCBID6xL3Tpm2w+SzLaaxFa9P/3EVdgPHWwPbENmUFWiAJesvwapfCQR8mgLaBwqF1YXk98DhkVABxbzHpgM84cQ3kwEO8KhYmoCfQ4Mt85gGAx+D78Q+x8QCFpgIycXMsMEL2l//Xz+y0/9NgmEcB1XR+yMtABSyBBHGuDG6xUWaJhc3unESgiceAqdoSv37+/x/URzHy9C8PBBYDog6E2AVYQbYCX/5cSoCvRGWV6TMmKIAPsqAJtIEH4AVhzT0vMbiet7fQsz3P9xAmLrgTTBsNYw+eRK9ejatHWCtAWtMDsalBmy5lTVeTbr702TZRUl83bSO9eFH/8mXDwtdZDasXHtyovH6tTctLrvLqVScsta/HNmHwkDUD8abejbqLwkKAduAmvOARmq7VTg9eML3h1D6Y9iwsvI5QrF+J/x0SEZcfG5sflSgt8kd5w4b61gUs94mL81m+Y2fjlh7ZG1T1xJGK8u9HjnxnPuzILijgLJB0qqpq/EkqM//EifmujpFczPxkcirxr1bVdX3iBlxZxtiWLbOBnVkWFcHbQJNc9DQ4/ynp+F+f98qaWdXA5Ootma+55kwPvZkchTQ5ka4QydJhuFCWnfp5hJbe79OjuW/Ar4CB4Aa4nWTvsiWBsIWdygL/P9vkDPwnb3PfWkZ2Sv/HCxwAXvcmnsXh20kOhql+g6qz6n+pOpalpSGuTEPLlXYoRadGKUAbBv5SgbG3U5hnnYkEXo8EhbcBqPD8qckMR40gHnW8LLSFKVre0Y2ChbIdgIXZCEhnR8HoSAWrs4dUjvkGGj19g5fOscCk6LahIDALzlOIjhKjqB8vWgwup8w8FIfkWmIabdcpaU0gkIjiscTFmMjofL6IOIkyxRTPGFMspbIoKy6HWIiOI3a7S3QrLisx0Egzpe7UqCi56kGRBpcDsDwKQocijER644ksDFycZK86hQufr0WYjGanozSUNGUlhMLD0rkoRqToDtQio7NTya2c4jGGSSyKkolkChcHUSHyE3aacRG5q/tZEQZUJPOAlFuqKKgkdzVGLm92vOEaaCO9MhjEIg5pQLj2iR5Co2PikrCsc5qMOqvFSzM5OgAAAA==') format('woff2'),
    url('./iconfont.woff?t=1551963575525') format('woff'),
    url('./iconfont.ttf?t=1551963575525') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
    url('./iconfont.svg?t=1551963575525#iconfont') format('svg'); /* iOS 4.1- */
  }

  .iconfont {
    font-family: "iconfont" !important;
    font-size: 16px;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }
`;

8、在src/App.js里面引入该全局样式组件

import { iconfontGlobal } from './static/iconfont/iconfont.js';

9、将Header组件里面的搜索、Aa、笔用iconfont代替

{/* 使用iconfont,文字是图标的unicode,类名都是iconfont */}

 

搜索框动画效果实现(聚焦搜索框变宽,搜索按钮有背景色,blur则变小)

使用react-transition-group插件的CSSTransition组件,用css实现动画效果

 

使用react-redux进行应用数据管理------组件的数据使用react-redux管理的话,组件就变成无状态组件了,使得性能大大提升

在项目中安装redux(数据框架)

在项目中安装react-redux(方便我们在react中使用redux)

需要定义的文件有index.js(store),reducer.js,constantTypes.js,

 

使用combineReducers完成对数据的拆分管理

对react-redux中的数据在浏览器端调试的插件是redux-devtools-extend,要想在浏览器中使用该插件调试redux中的数据,需要在创建store的时候,进行配置

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(react,react中的基本知识,生命周期,redux)