React学习笔记(二)

170 阅读4分钟

类组件生命周期钩子函数

constructor(props)

类组件的构造函数,是第一步执行的,这里可以进行state的初始化以及对事件绑定this

constructor(props) {
    super(props)
    this.state = {
      name: 'tom'
    }
    this.eventHandler = this.eventHandler.bind(this)
}

getDerivedStateFromProps(props, state)

会在 render 方法之前调用,无论是挂载阶段还是更新阶段,它的存在只有一个目的:让组件在 props 变化时更新 state

static getDerivedStateFromProps(props, state) {
    console.log('这里可以获得变化后的props')
    console.log('首次渲染 和 props 变化时就会触发')
    return state
}

shouldComponentUpdate(nextProps, nextState)

只在更新阶段,首次渲染不会调用,render之前调用,函数返回一共布尔值,决定是否继续进行render

shouldComponentUpdate(nextProps, nextState) {
    console.log('如果返回false 就不会进行render更新')
    return true
}

render()

组件生命周期渲染阶段执行的函数,返回值为组件要渲染VirtualDOM

render() {
    return (
        <div>hello</div>
    )
}

getSnapshotBeforeUpdate(prevProps, prevState)

在 render() 之后,但是在输出到 DOM 之前执行,用来获取渲染之前的快照。当我们想在当前一次更新前获取上次的 DOM 状态,可以在这里进行处理,返回值可以在 componentDidUpdate 方法中的第三个参数中获取,就是说在组件更新之后可以拿到这个值再去做其他事情。

getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('getSnapshotBeforeUpdate render之后 dom更新之前')
    console.log('可以在这里获取到更新前的dom 这个钩子不常用')
}

componentDidUpdate()

会在 DOM 更新后立即调用,首次渲染不会调用该方法。我们可以在这个函数中对渲染后的 DOM 进行操作

componentDidUpdate() {
    console.log('componentDidUpdate DOM 更新后执行 首次渲染不会执行')
    console.log('这里可以获取到更新后的DOM')
}

componentDidMount()

在组件挂载后调用

componentDidMount() {
    console.log('组件第一次挂载后')
}

componentWillUnmount()

会在组件卸载及销毁前调用,我们可以在这里做一些清理工作,如:组件内的定时器、未完成的请求等

componentWillUnmount() {
    console.log('组件销毁前')
}

受控表单、非受控表单

根据表单和state数据的状态关联关系,分为受控组件和非受控组件

  • 受控表单 :表单控件中的值由组件的 state 对象来管理,state对象中存储的值和表单控件中的值时同步状态的

  • 非受控表单:表单元素的值由 DOM 元素本身管理

受控表单类似于Vue的双向绑定

双向数据绑定是指,组件类中更新了状态,DOM 状态同步更新,DOM 更改了状态,组件类中同步更新。组件 <=> 视图。

要实现双向数据绑定需要用到表单元素和 state 状态对象。

受控表单

表单控件中的值由组件的 state 对象来管理,state对象中存储的值和表单控件中的值时同步状态的,当表单变化时state状态也会同步变化。

class App extends Component {
  constructor () {
    this.state = { username: "" }
    this.nameChanged = this.nameChanged.bind(this)
  }
  
  nameChanged (e) {
    this.setState({username: e.target.value})
  }
  render() {
    return (
      <form>
        <p>{this.state.username}</p>
        {/*  */}
        <input type="text" value={this.state.username} onChange={this.nameChanged}/>
      </form>
    )
  }
}

非受控表单

表单元素的值由 DOM 元素本身管理。

class App extends Component {
  constructor () {
    this.onSubmit = this.onSubmit.bind(this)
  }
  onSubmit(e) {
    console.log(this.username.value)
    e.preventDefault();
  }
  render(
    <form onSubmit={this.onSubmit}>
      <input type="text" ref={username => this.username = username}/>
    </form>
  )
}

获取组件实例

通过ref和createRef()可以获取到组件实例,可以用来获取标签DOM

class Input extends Component {
  constructor() {
    super()
    this.inputRef = React.createRef()
  }
  render() {
    return (
      <div>
        <input type="text" ref={this.inputRef} />
        <button onClick={() => console.log(this.inputRef.current)}> button </button>
      </div>
    )
  }
}

路由

依赖 cnpm install react-router-dom

必须引入路径组件(BrowserRouter或者HashRouter),使用BrowserRouter或者HashRouter包括起全部内容

这两个组件在开发环境中没有任何区别,在生产环境中的区别是hash在路径上会有一个#号,而browser没有

import React from 'react';
import { BrowserRouter, Route, Link } from 'react-router-dom';
function Index() {
 return <div>首页</div>;
}
function News() {
 return <div>新闻</div>;
}
function App() {
  return (
    <BrowerRouter>
      <div>
        <Link to="/index">首页</Link>
        <Link to="/news">新闻</Link>
      </div>
      <div>
        <Route path="/index" component={Index}/>
        <Route path="/news" component={News}/>
      </div>
    </BrowerRouter>
  );
}

路由嵌套

子路由组件通过props.match.path获取到父级路由组件的路径

function News(props) {
  return (
    <div>
      <div>
        <Link to={`${props.match.url}/company`}>公司新闻</Link>
        <Link to={`${props.match.url}/industry`}>行业新闻</Link>
      </div>
      <div>
        <Route path={`${props.match.path}/company`} component={CompanyNews} />
        <Route path={`${props.match.path}/industry`} component={IndustryNews}/>  
      </div> 
    </div>
  );
}

function CompanyNews() {
 return <div>公司新闻</div>
}
function IndustryNews() {
 return <div>行业新闻</div>
}

路由传参

{/* 父级路由组件 */}
<Link to={`/detail?id=${item.id}`}>{item.title}</Link>
{/* 子路由组件 */}
import url from 'url'
class Detail extends Component {
  constructor(props) {
    super(props);
    const { query } = url.parse(this.props.location.search, true);
    console.log(this.props.location.serach); // ?id=1
    console.log(query); // {id: 1}
  }
}

路由重定向

用Redirect组件

import { Redirect } from 'react-router-dom';

class Login extends Component {
  render() {
    if (this.state.isLogin) {
      return <Redirect to="/"/>
    }
  }
}

exact

exact 属性表示路由使用 精确匹配模式,非 exact 模式下 '/' 匹配所有以 '/' 开头的路由

如果不使用exact,/about 会匹配到 index和about两个组件都会显示了

<Route path="/" exact component={IndexPage} />
<Route path="/about" exact component={AboutPage} />

Link组件

Link 组件用来处理 a 链接 类似的功能(它会在页面中生成一个 a 标签),但设置这里需要注意的,react-router-dom 拦截了实际 a 标签的默认动作,然后根据所有使用的路由模式(Hash 或者 HTML5)来进行处理,改变了 URL,但不会发生请求,同时根据 Route 中的设置把对应的组件显示在指定的位置 

 to 属性类似 a 标签中的 href

NavLink

NavLink 与 Link 类似,但是它提供了两个特殊属性用来处理页面导航

activeStyle

当前 URL 与 NavLink 中的 to 匹配的时候,激活 activeStyle 中的样式也就是说被选中的时候

activeClassName

与 activeStyle 类似,但是激活的是 className

<NavLink to="/" exact
  activeStyle={{
     color: 'red'
  }}
>首页</NavLink>

<NavLink to="/about" exact
  activeClassName="active-class"
>关于</NavLink>