React基础(路由,组件,事件)

基本指令

for if show hidden 000

status 000

props 000

事件 000

ref

  • ref是一个React的非常特殊的属性,这个属性一定是接受一个回调函数,这个回调函数会在组件渲染时进行执行一遍,在从视图中撤出来时会执行一遍
  • 不要企图在函数式组件中使用ref属性来进行回调函数的绑定,因为函数式组件是没有实例的,准确的说函数式组件不是一个真正的类
  • 虽然无法对函数式组件使用ref属性,但是为函数式组件里面的HTML元素和类组件使用ref属性是可以的
  • ref从一定程度上增加了组件之间的耦合性,导致难以分离,所以如果可以用props来处理的事情,尽量不要用ref来处理
  • 在以前的一些React版本通过this.refs可以获取一个字符串,这个方法在将来会被抛弃所以请不要使用,即便是ref可以设置为一个字符串,但是强烈建议用回调函数
  • 官方强调不要用ref直接去做非常明显的事件,比如说Dialog组件打开和关闭的open()和close()可以通过isOpen去控制,而不是明显的函数处理
ref设置成字符串(不建议使用这种方式)
class BoxCom extends React.Component {
  constructor(props){
    super(props)
  }

  testRef(e){
    console.log('test-ref',this.refs )
  }

  render(){
    return (
      <div>
          <input type="text" ref="ipt" />
          <button onClick={this.testRef.bind(this)}>获取dom5</button>
      </div>
    )
  }
}

这里写图片描述

ref设置成回调函数

ref属性可以设置为一个回调函数,这也是官方强烈推荐的用法;这个函数执行的时机为:
- 组件被挂载后,回调函数被立即执行,回调函数的参数为该组件的具体实例。
- 组件被卸载或者原有的ref属性本身发生变化时,回调也会被立即执行,此时回调函数参数为null,以确保内存泄露。

class BoxCom extends React.Component {
  constructor(props){
    super(props)
    this.state = { }
    this.inputDom = null
  }

  testRef(e){
    console.log( 'inputDom' , this.inputDom );
    console.log( 'inputDom-value' , this.inputDom.value );
  }


  render(){
    return (
      <div>
          <input type="text" ref={(inputDom)=>{ this.inputDom = inputDom }} />
          <button onClick={this.testRef.bind(this)}>获取dom5</button>
      </div>
    )
  }
}

这里写图片描述

父组件获取子组件的ref和子组件内部的ref

父组件


import React from 'react';
import PropTypes from 'prop-types'
import GrandSon from './grandSon'

class BoxCom extends React.Component {
  constructor(props){
    super(props)
    this.state = { }
    this.GrandSonDom = null
  }

  boxGrandSon(){
    console.log( '获取子组件上的ref' , this.GrandSonDom )
    console.log( '获取子组件里面的ref' , this.GrandSonDom.grandSonInput, this.GrandSonDom.grandSonInput.value )
  }

  render(){
    return (
      <div>
          <GrandSon width={500} height={100} ref={(dom)=>{ this.GrandSonDom = dom }} ></GrandSon>  
          <button onClick={this.boxGrandSon.bind(this)}>box-grandSon</button>
      </div>
    )
  }
}


BoxCom.propTypes = {
  width: PropTypes.number
  height: PropTypes.number
}
export default BoxCom;

子组件


import React from 'react';
import PropTypes from 'prop-types'

class grandSon extends React.Component {
  constructor(props){
    super(props)
    this.grandSonInput = null
  }

  btnClick(){
    console.log( '获取本组件内的ref' , this.grandSonInput, this.grandSonInput.value )
  }

  render(){
    return (
      <div style={{border:'3px solid red',width:this.props.width , height:this.props.height}} >
        <input type="text" ref={(ipt)=>{ this.grandSonInput = ipt }} />
        <button onClick={this.btnClick.bind(this)}>grandSon</button>
      </div>
    )
  }
}


//规定props属性的值必须是数字类型
grandSon.propTypes = {
  width: PropTypes.number,
  height: PropTypes.number
}


export default grandSon;

这里写图片描述

路由 000

嵌套路由

import React from 'react';
import { Router, Route , IndexRoute } from 'dva/router';
import Login from './routes/Login';
import Register from './routes/Register';
import Main from './routes/Main';
import Path from './routes/path';
import Admi from './routes/member/admi';
import Technical from './routes/member/technical';
import Marketing from './routes/member/marketing';


function RouterConfig({ history }) {
  return (
    <Router history={history}>
      <Route path="/" component={Login}></Route> 
      <Route path="/Register" component={Register}></Route> 
      <Route path="/main" component={Main} >   当路由是/main的时候会加载Main组件和Marketing组件
        <IndexRoute component={Marketing} />
        <Route path="/admi" component={Admi} />
        <Route path="/marketing" component={Marketing} />
        <Route path="/technical" component={Technical} />
      </Route>

    </Router>
  );
}

export default RouterConfig;

Main.js

import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'dva'
import { Link } from 'dva/router'
import './main.css'; 
import { Menu, Icon, Switch , Row , Col } from 'antd';
import { browserHistory } from 'react-router'

const SubMenu = Menu.SubMenu;
var ck = require('js-cookie')

class Sider extends React.Component {
  state = {
    theme: 'dark',
    current: '1',
    username:''
  }
  changeTheme = (value) => {
    this.setState({
      theme: value ? 'dark' : 'light',
    });
  }
  handleClick = (e) => {
    this.setState({
      current: e.key,
    });
  }

  componentWillMount(){
    // console.log( ck.get('user') )
    // var user = ck.get('user') && JSON.parse(ck.get('user'))
    // if( !user ){ browserHistory.push('/'); return  }
    // this.setState({ username:user.name })
  }

  logoOut(){
    // ck.remove('user')
    browserHistory.push('/')
  }

  render() {
    return (
      <div style={{height:'100%',width:'100%',overflow:'hidden'}}>
        <div style={{ backgroundColor:'#36485d', color:'white',height:50,fontSize:'22px',lineHeight:'50px' }}>

          {this.props.children}   //路由的占位符
        </div>
      </div>
    );
  }
}

export default connect(({ main }) => ({ main }))(Sider)

路由重定向Redirect

  • 组件用于路由的跳转,即用户访问一个路由,会自动跳转到另一个路由。
<Route path="inbox" component={Inbox}>
  {/* 从 /inbox/messages/:id 跳转到 /messages/:id */}
  <Redirect from="messages/:id" to="/messages/:id" />
</Route>

IndexRedirect 组件

  • IndexRedirect组件用于访问根路由的时候,将用户重定向到某个子组件。
<Route path="/" component={App}>
  <IndexRedirect to="/welcome" />
  <Route path="welcome" component={Welcome} />
  <Route path="about" component={About} />
</Route>

路由跳转

<Route path="/boys/:boyName" component={Boy}/>
<Link to="/boys/宋仲基">宋仲基</Link>
  • 查询参数
<Route path="/country" component={country}/>
<Link to={{ pathname:'country' , query:{addr:'china'} }}>国家</Link>

按钮跳转 000

<Link to="/about" activeStyle={{color: 'red'}}>About</Link>
<Link to="/about" activeClassName="active">About</Link>    //使用activeClassName指定当前路由的Class。

js实现跳转 000

import { browserHistory } from 'react-router';
browserHistory.push('/some/path');
如果链接到根路由/,不要使用Link组件,而要使用IndexLink组件。
这是因为对于根路由来说,activeStyle和activeClassName会失效,或者说总是生效,因为/会匹配任何子路由。而IndexLink组件会使用路径的精确匹配。
<IndexLink to="/" activeClassName="active">
  Home
</IndexLink>
或者
<Link to="/" activeClassName="active" onlyActiveOnIndex={true}>
  Home
</Link>

表单处理

<form onSubmit={this.handleSubmit}>
  <input type="text" placeholder="userName"/>
  <input type="text" placeholder="repo"/>
  <button type="submit">Go</button>
</form>

方法一
import { browserHistory } from 'react-router'
  handleSubmit(event) {
    event.preventDefault()
    const userName = event.target.elements[0].value
    const repo = event.target.elements[1].value
    const path = `/repos/${userName}/${repo}`
    browserHistory.push(path)
  },

方法二
export default React.createClass({

  // ask for `router` from context
  contextTypes: {
    router: React.PropTypes.object
  },

  handleSubmit(event) {
    // ...
    this.context.router.push(path)
  },
})

路由传参 000

组件 000

组件传参 000

  • URL的查询字符串/foo?bar=baz,可以用this.props.location.query.bar获取

组件复用 000

生命周期

  • componentWillMount() //将被插入真实dom
  • componentDidMount() //已插入真实dom
  • componentWillUpdate(object nextProps, object nextState) //组件将被更新
  • componentDidUpdate(object prevProps, object prevState) //组件已经被更新
  • componentWillUnmount() //将被移除真实dom
    特殊状态处理函数
  • componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
  componentWillReceiveProps(arg){
    console.log('即将接收props',arg);  //arg的值是传入的props
  }
  • shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
  shouldComponentUpdate( arg ){
    // 需要return false或true
    console.log('组件是否被更新' , arg )  //arg的值是传入的最新props
    return true   //true则更新组件 , false则不更新组件
  }

redux

  • index.js
import dva from 'dva';
import './index.css';
import { browserHistory } from 'dva/router'
// 1. Initialize
const app = dva({
  history: browserHistory,
});

// 2. Plugins
// app.use({});

// 3. Model
app.model(require('./models/app'));   

// 4. Router
app.router(require('./router'));

// 5. Start
app.start('#root');
  • app.js
import {login} from '../services/example';
import { routerRedux } from 'dva/router'

const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout));  

export default {
  namespace: 'app',
  state:
  {
    loginLoading:false,
    num:123456
  },
  subscriptions: {
    setup ({ dispatch }) {
    },
  },
  effects: {
    *login ({payload}, { call, put }) {
      yield put({ type: 'showLoginLoading' })
      yield call(delay,2000) 
      yield put({ type: 'hideLoginLoading' })
      yield call(delay,1000)
      yield put(routerRedux.push('/main'))
    }},
  reducers: {
    add( state , { payload:value }){
      console.log( 'add' , value ) 
      return { num:value }
    },
    showLoginLoading (state) {
      return {
        loginLoading: true,
      }
    },
    hideLoginLoading (state) {
      return {
        loginLoading: false,
      }
    },
  },
}
  • admi.js
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'dva'
import TestCom from '../../components/test'
import BoxCom from '../../components/box'
import { request } from '../../utils/request';
// import {delay} from '../utils/request';
import { Button, Row, Form, Input } from 'antd' 



const FormItem = Form.Item 

const Login = ({
  app,
  dispatch,
  form:{
    getFieldDecorator,
    validateFieldsAndScroll,
  },
  myNum
}) => {


  function myClick(){
    // request('/api/test',{
    //   method:'POST',
    //   headers: {
    //     'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8" 
    //   },
    //   body:"name=tom&age=19",
    //   // body:{name:'jack'}
    // }).then((data)=>{
    //   console.log('data',data)
    // })
  }

  function testClick(e){
    // console.log('testClick', this.props.location.query )
  }

  function routerWillLeave(){
    alert('确认是否要离开')
  }

  function changeRedux(){
    var num = app.num + 1
    dispatch({
      type:'app/add',
      payload:num
    })

    console.log( 'app' , app );
  }

  var num = 120

  return (
    <div style={styles.login}>

      <div style={{border:'1px solid blue'}}>
        <div>{ num }</div>
        <div>app--{ app.num }</div>
        <button onClick={changeRedux.bind(this)}>redux</button>
      </div>
      {/* <BoxCom width={500} height={322} app={{name:'tom'}}></BoxCom> */}
      {/* <form action="post" ></form> */}

    </div>
  )
}

Login.propTypes = {
  form: PropTypes.object,
  app: PropTypes.object,
  dispatch: PropTypes.func
}

const styles = {
  login:{
    width:'100%',
    height:'100%',
    justifyContent:'center',
    alignItems:'center',
    // fontSize:'25px',
    // color:'red'
  }
}

export default connect(({ app }) => ({ app }))(Form.create()(Login))

这里写图片描述
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值