小学习

166 阅读5分钟

#基于react+js+Ant Design的后台管理系统#

1,react没有双向数据绑定,需要监听

<Input
  className="from__item"
  suffix={<i className="icon-Key"></i>}
  placeholder="请输入登录密码"
  type="password"
  value={passWord}
  onChange={ e => this.passWordChanged(e) }
/>
// 有时候会出现这种情况,获取到的target为null
// 因为React里面的事件并不是真实的DOM事件,
// 而是自己在原生DOM事件上封装的合成事件。
// 使用e.persist();将当前的合成事件从事件池中移除了就可以获取到了
handleKeyword = e => {
    e.persist();
    this.setState({
      keyword: e.target.value,
    })
  }

2,this的指向可以通过箭头函数来保持原来的指向,也可以用bind(this, data)直接绑定this的指向,在handleSubmit(this, data)里面,this一定是第一个参数!

<Button 
    type="primary" 
    className="cert-btn" 
    onClick={this.handleSubmit.bind(data, this)}
>
    登录
</Button>

3,利用mock.js来实现假数据测试
(1),首先还是先安装依赖 npm install -D mockJs
(2),新建mock文件夹,新建mock.js文件
(3),编写mock
` import Mock from 'mockjs';

Mock.mock(/\/todoList.mock/, {
    code': 0,  
    'data': {
        'list|1-10': [{
            // 属性 id 是一个自增数,起始值为 1,每次增 1
            'id|+1': 1,
            'title': '前端人人@id',
            'status': 1
        }]
    },
    'message': '操作成功',
    'systemDate': new Date().getTime()
});

4,redux-persist
redux-persist会将redux的store中的数据缓存到浏览器的localStorage中。
实现方式主要是依靠两个方法:persistStorepersistReducer,使用persistReducer时需要指定persistConfig,这一项就是你需要缓存的数据处理项,它有着黑白名单的处理方式,还需要一个storage的协助:
在main.js中用标签包着

import store from "./store";
import { persistStore } from 'redux-persist'; //从redux-persist解构出persistStore()方法,该方法结合PersistGate标签使用会将redux的数据缓存到localStorage 
//引入PersistGate标签
import { PersistGate } from 'redux-persist/es/integration/react';  

const persistor = persistStore(store);
ReactDOM.render(
  <Provider store={store}>
    <PersistGate persistor={persistor}>
      <Routes />
    </PersistGate>
  </Provider>,
  document.getElementById('root'),
)

在store.js文件中引用

import { createStore, applyMiddleware } from 'redux'  //异步 actions
import rootReducer from '@reducers'
import { persistReducer } from 'redux-persist';
import storage from 'redux-persist/es/storage'

// BLACKLIST
const persistConfig = {
    key: 'root', // key是放入localStorage中的key
    storage: storage, // storage简单就可以理解成localStorage的功能封装吧,不过有时候由于版本问题,必要在后一个storage上加一个default属性,可以在console中打出来判断是否需要加
    blacklist: ['navigation']//navigation不会被存入缓存中,其他会,适用于少部分数据需要实时更新
};
// WHITELIST
const persistConfig = {
  key: 'root',
  storage: storage,
  whitelist: ['navigation']  
};
<!--可直接使用-->
const reducer = persistReducer(persistConfig, rootReducer);
<!--使用combineReducers-->
const reducers = combineReducers({
  depReducer: persistReducer(persistConfig, depReducer)
});
<!--使用中间件applyMiddleware创建store-->
const store = createStoreWithMiddleware(persistReducer(storageConfig, rootReducer), initialState)

5,当路由发送改变时页面置顶
生命周期componentDidUpdate()与生命周期componentWillReceiveProps()的区别:
componentDidUpdate()---是在组件接受新的props之后触发,并且更新状态是同步的;
componentWillReceviceProps()---是在组件接受新的props之前触发,并且更新状态是异步的;
这点区别非常重要,也是componentWillReceiveProps生命周期被废弃的重要原因(可能导致某些问题), 所以推荐使用componentDidUpdate
app.js文件,在componentDidUpdate生命周期进行判断当前路由是否是上一个路由,如果不是则获取当前页面的dom节点置顶

componentDidUpdate(prevProps) {
    if (this.props.location.pathname !== prevProps.location.pathname) {
        document.getElementById("page-content").scrollTo(0, 0);
    }
}

6,react的生命周期

react可分为三个状态:

  • Mounting:已插入真实 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真实 DOM

react生命周期的方法有:

  1. componentWillMount 在渲染前调用,在客户端也在服务端。
  2. componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。
  3. componentWillReceiveProps 在组件接收到一个新的 prop (更新前)时被调用。这个方法在初始化render时不会被调用。
  4. shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。可以在你确认不需要更新组件时使用。
  5. componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。是在组件接受新的props之前触发,并且更新状态是异步的。
  6. componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。是在组件接受新的props之后触发,并且更新状态是同步的。
  7. componentWillUnmount在组件从 DOM 中移除之前立刻被调用。

栗子:

class Content extends React.Component {
  componentWillMount() {
      console.log('Component WILL MOUNT!')
  }
  componentDidMount() {
       console.log('Component DID MOUNT!')
  }
  componentWillReceiveProps(newProps) {
        console.log('Component WILL RECEIVE PROPS!')
  }
  shouldComponentUpdate(newProps, newState) {
        return true;
  }
  componentWillUpdate(nextProps, nextState) {
        console.log('Component WILL UPDATE!');
  }
  componentDidUpdate(prevProps, prevState) {
        console.log('Component DID UPDATE!')
  }
  componentWillUnmount() {
         console.log('Component WILL UNMOUNT!')
  }
 
    render() {
      return (
        <div>
          <h3>{this.props.myNumber}</h3>
        </div>
      );
    }
}

7,二级菜单的路由配置

import React from 'react'
import { Router, Route, IndexRoute, hashHistory, Redirect, IndexRedirect } from 'react-router'
import { base } from '@configs/base'; //基础管理的相关页面总入口文件
import { routes } from './router.js'; //引入路由文件

export function fliterRouter(routers, arr) { // 过滤路由
  routers.forEach((item) => {
  <!--含有子菜单的一级菜单-->
    if (item.children) {
    <!--配置show字段用于判断是否需要显示该一级菜单-->
        if (!item.show){
          const router = <Route key={item.path} path={item.path} component={item.component} onEnter={requireAuth}  config={item} />
            arr.push(router)
        }
        fliterRouter(item.children, arr)
    } else {
      const router = <Route key={item.path} path={item.path} component={item.component} onEnter={requireAuth} config={item} />
      arr.push(router)
    }
  })
  return arr
}

export default () => (
  <Router history={hashHistory}>
    <Route path="/" component={base.app} onEnter={requireAuth}>
      <IndexRedirect to="/business/busManagement" />
      {fliterRouter(routes, [])}
    </Route>
      <Route path="/test" component={base.example} />
    <Route path="/login" component={base.loginFrom} />
    <Route path="*" component={base.notfound} />
  </Router>
)

8,redux的简单使用
在action.js文件中使用createAction创建action

import { createAction } from 'redux-actions'

// login 登陆
export const requestLogin = createAction('request login')
export const recevieLogin = createAction('receive login')
export const loading = createAction('loading')

在reducer.js文件中使用handleActions处理action

import {handleActions} from 'redux-actions'

// 登陆返回结果
const loginState = () => ({loading: false})
export const loginResponse = handleActions({
    'request login'(state, action) {
        return {...state, loading: true}
    },
    'receive login'(state, action) {
        // eslint-disable-next-line no-unused-vars
        console.log(action);
        const {req, res} = action.payload
        return {menu: res.data.menu,userName:res.data.userName ,loading: false}
    },
    'loading'(state, action) {
        return {loading: false}
    }
}, loginState())

在login.js文件中通过this.props.dispatch调用action的login()方法,保存数据(修改/更新数据)到store里

this.props.dispatch(login(formData, (res) => {
<!--登录成功跳转到首页-->
    hashHistory.push("/business/busManagement")
}, (res) => {
    message.warning(res.msg);
    this.props.dispatch(loading({loading: false}))
}))