react的使用笔记

224 阅读8分钟

React

以下只是我对react的学习和阅读react文档之后的一个笔记,如果有什么写的不对的地方,可以的话麻烦请告诉我一下,谢谢。
(这里只提到了关于react类形式用法,以后可能也会写一些关于hook的总结)

react项目的组成

react 的项目有两种实现形式,一种是类形式(class组件),一种是hook形式(函数组件)

ReactDOM.render方法

ReactDOM.render 方法传入两个参数:第一个参数是要渲染的内容,第二个参数是要插入的节点

ReactDOM.render(
  <h1>Hello World</h1>,
  document.getElementById('root')
);

JSX语法

JSX语法指的是javascript+XML语法(简单理解为HTML)

const world = 'world!';
ReactDOM.render(
  <h1>Hello {world}</h1>,
  document.getElementById('root')
);

其中{}表示javascript的表达式,搭配html的标签实现页面内容的编写

编写class组件

每一个class组件都会导出一个类,继承的react下的component类,并且定义一个render函数,返回一个节点

// App 组件
import React from 'react';

export default class App extends React.Component{
  render() {
    return(
        <h1>
          Hello World
        </h1>
    )
  }
}

使用组件(以标签的形式使用组件)

import App from './app';

ReactDOM.render(
    <App/>,
    document.getElementById('root')
);

state状态

react组件中储值的方式有两种:state和props。其中state是组件自身维护的状态,而props则是常用于组件之间复用组件的数据传递,react组件不允许自身修改props

// 定义state
import React from 'react';

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      title: 'react props'
    };
  }
  // 通过this.state调用state状态值
  render() {
    return (
        <div>
          <h1>{this.state.title}</h1>
          <button onClick={this.changeTitle}>修改标题</button>
        </div>
    );
  }
  // 修改state状态
  changeTitle = () => {
    this.setState({
      title: 'change title'
    })
  }
}

this指向问题

在上面的changTitle事件声明中,使用了箭头函数,是为了保证函数执行时this的指向为react组件自身。也可以使用下面的bind写法

import React from 'react';

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      title: 'react props'
    };
  }
  // 通过this.state调用state状态值
  render() {
    return (
        <div>
          <h1>{this.state.title}</h1>
          <button onClick={this.changeTitle.bind(this)}>修改标题</button>
        </div>
    );
  }
  // 修改state状态
  changeTitle() {
    this.setState({
      title: 'change title'
    })
  }
}

在使用或声明react组件自身的属性和方法时都要注意this指向问题

组件之间的通讯传递

组件可以通过props属性来传递数据

// PropsDemo 组件
import React from 'react';

export default  class PropsDemo extends React.Component {
  render() {
    return(
        <div>
          <h1>{this.props.title}</h1>
        </div>
    )
  }
}
// App 组件
import React from 'react';
import PropsDemo from "./propsDemo";

export default class App extends React.Component{
  constructor() {
    super();
    this.state = {
      title: 'react props'
    };
  }
  render() {
    return(
      <div>
        <PropsDemo title={this.state.title}/>
      </div>
    )
  }
}

上面的代码中,通过props属性从父组件(App)传递给子组件(PropsDemo)
props的只读性:react组件自身是不能修改props属性的值
当需要通过子组件向父组件传递值时,我们可以通过事件回传的方式实现

// PropsDemo组件
import React from 'react';

export default class PropsDemo extends React.Component {
  changeTitleHandler = () => {
    this.props.changeTitleHandler('react props title after changed');
  };
  
  render() {
    return (
      <div>
        <h1>{this.props.title}</h1>
        <button onClick={this.changeTitleHandler}>修改标题</button>
      </div>
    );
  }
}
// App组件
import React from 'react';
import PropsDemo from "./propsDemo";

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      title: 'react props'
    };
  }
  
  changeTitle = (title) => {
    this.setState({
      title: title
    });
  };
  
  render() {
    return (
        <div>
          <PropsDemo title={this.state.title} changeTitleHandler={this.changeTitle}/>
        </div>
    );
  }
}

生命周期

生命周期方法是react组件运行过程中特定的阶段执行的方法,我们可以重写这些方法,实现项目的开发需求
在react的官方文档中将这些方法分为两类:常用和罕见。这里先说常用的

render:render方法是react组件中必须实现的方法。这个方法是一个纯函数方法(不做任何状态的改变,浏览器交互等),根据state和props的变化返回渲染元素
constructor:构造函数主要有两种用途,初始化state和为事件绑定实例
componentDidMount:在组件挂载完之后就会调用componentDidMount方法,可以在这里实例化请求和添加订阅
componentDidUpdate:当组件更新时调用该方法,可以对state和props做改变前后的对比。该方法接受三个参数,第一个是prevProps,第二个是prevState,第三个是snapshot(不常用)
componentWillUnmount:当组件即将被卸载时,该方法会被调用。如果组件中有已添加的订阅,可以在这里取消订阅

事件处理

在react的事件绑定中,传递的不是一个字符串,而是一个事件处理器

<div>
  <PropsDemo title={this.state.title} changeTitleHandler={this.changeTitle}/>
</div>

在阻止默认事件的时候,不能通过返回false方式,只能显式的时候preventDefault

function changeTitle(e) {
  e.preventDefault();
}

在绑定事件中,可以通过箭头函数和bind的方法来指定实例

// bind方式
class x extends React.Component {
  constructor() {
    super();
    this,handler = this.handler.bind(this);
  }
  handler() {
    console.log(this);
  }
}
// 箭头函数
class x extends React.Component {
  handler = () => {
    console.log(this);
  }
}

在react的事件绑定中,如果在绑定时直接加()是会在渲染完成之后直接触发的,并不会按照我们设计好的情境下触发。当我们需要向事件处理器传递参数时,我们也可以使用箭头函数和bind的形式

<button onClick={ () => this.print('the text') }></button>
<button onClick={ this.print.bind(this, 'the text') }></button>

条件渲染

在react组件中,使用条件渲染可以依据不同的状态值渲染不同的组件内容

// IfDeo 组件
import React from 'react';

export default class IfDemo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isLogin: false
    }
  }
  render() {
    return (
      <div>
        {
          this.state.isLogin
            ? <h3>已登录</h3>
            : <h3>未登录</h3>
        }
      </div>
    )
  }
}

如果你在某个状态下不想渲染某个组件,可以让render直接返回null

列表渲染

当我们想要渲染多个相同的组件或列表的时候,使用列表渲染会很简单

// ListDemo 组件
import React from "react";

export default class ListDemo extends React.Component {
  render() {
    const list = [1, 2, 3, 4, 5];
    return (
      <ul>
        {
          list.map((val, index) => <li key={index}>{val}</li> )
        }
      </ul>
    )
  }
}

react要求我们在使用列表渲染的时候需要指定key值,兄弟节点之间的key值是唯一的。在这里我们指定索引为key。管文文档中提到,如果项目列表数据可能发生改变的话,建议不要使用索引。如果数据中有id或者其他唯一的值,我们可以指定该值为key。
文档中提到了key的作用是帮助react识别哪些元素发生了改变了,从而快速的定位和更新dom树深入解析为什么 key 是必须的

表单组件

在react中表单组件分为两种:受控组件和非受控组件。
在html开发中,我们经常使用操作dom的方法来对表单的值进行处理。而在react中我们可以通过state来保存表单组件的值,这就是受控组件。
而不是通过state来操作的组件,则是非受控组件。

受控组件

// FormDemo 组件
import React from "react";

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {};
    this.changeHandler = this.changeHandler.bind(this);
  }
  changeHandler(e) {
    this.this.setState({
      username: e.target.value
    })
  }
  render() {
    return (
      <form>
        <label>
          用户名
          <input type="text" name='username' onChange={ this.changeHandler }/>
        </label>
        <button onClick={ this.printHandler }>打印</button>
      </form>
    ) 
  }
}

上面的代码中,input的值在改变的之后通过绑定的事件将值保存到了state上。在react中,大部分的表单组件都是以这样的形式来保存。例如textarea,checkbox,select

import React from "react";

export default class FormDemo extends React.Component {
  constructor() {
    super();
    this.state = {
      fruit: 'apple',
      isGoing: true,
      isFast: false
    };
    this.changeHandler  = this.changeHandler.bind(this);
    this.printHandler = this.printHandler.bind(this);
  }
  changeHandler(e) {
    const name = e.target.name;
    const value = (name === 'isGoing' || name === 'isFast') ? e.target.checked : e.target.value;
    this.setState({
      [name]: value
    })
  }
  printHandler(e) {
    e.preventDefault();
    console.log(this.state);
  }
  render() {
    return (
      <form>
        <label>
          用户名
          <input type="text" name='username' onChange={ this.changeHandler }/>
        </label>
        <label>
          密码
          <input type="text" name='password' onChange={ this.changeHandler }/>
        </label>
        <select name="fruit" value={ this.state.fruit } onChange={ this.changeHandler }>
          <option value="apple">苹果</option>
          <option value="banana">香蕉</option>
          <option value="watermelon">西瓜</option>
        </select>
        <textarea name="content" value={ this.state.content } onChange={ this.changeHandler }></textarea>
        <label>
          快速
          <input name="isFast" type="checkbox" checked={ this.state.isFast } onChange={ this.changeHandler }/>
        </label>
        <label>
          前进
          <input name="isGoing" type="checkbox" checked={ this.state.isGoing } onChange={ this.changeHandler }/>
        </label>
        <div>
          <label>
            1
            <input type="radio" name="nums" value='1' onChange={ this.changeHandler } />
          </label>
          <label>
            2
            <input type="radio" name="nums" value='2' onChange={ this.changeHandler } />
          </label>
          <label>
            3
            <input type="radio" name="nums" value='3' onChange={ this.changeHandler } />
          </label>
        </div>
        <button onClick={ this.printHandler }>打印</button>
      </form>
    )
  }
}

非受控组件

而当使用input[file]接收文件时,就无法使用state来保存,需要通过非受控组件来获取文件
非受控组件实际上就是就是将数据保存在dom节点上,通过操作dom节点的方式来获取数据。而在react中想要操作dom,可以通过ref

// RefDemo 组件
import React from "react";

export default class RefDemo extends React.Component {
  constructor() {
    super();
    this.username = React.createRef();
    this.printHandler = this.printHandler.bind(this);
  }
  printHandler(e) {
    e.preventDefault();
    console.log(this.username.current.value);
  }
  render() {
    return (
      <form>
        <input type="text" ref={ this.username }/>
        <button onClick={ this.printHandler }>打印</button>
      </form>
    );
  }
}