React上手 —— 基础篇

适用范围:熟悉es6语法、最好是Vue开发者

环境:

这就其实指能快速run react 语法的环境:

  1. codepen:缺点是没有语法提示(或许是我自己不会配?)
  2. react脚手架
第一个项目:
ReactDOM.render(
  

Hello, world!

, document.getElementById('root') );

JSX简介:

const element = 

Hello, world!

;

它被称为 JSX, 一种 JavaScript 的语法扩展。 我们推荐在 React 中使用 JSX 来描述用户界面。JSX 乍看起来可能比较像是模版语言,但事实上它完全是在 JavaScript 内部实现的。

在 JSX 中使用表达式:

function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

const element = (
  

Hello, {formatName(user)}!

); ReactDOM.render( element, document.getElementById('root') );
function getGreeting(user) {
  if (user) {
    return 

Hello, {formatName(user)}!

; } return

Hello, Stranger.

; }

jsx可以作为参数 或者返回值。

JSX 属性

const element = 
;

或者打括号定义:

const element = ;

警告:
因为 JSX 的特性更接近 JavaScript 而不是 HTML , 所以 React DOM 使用 camelCase 小驼峰命名 来定义属性的名称,而不是使用 HTML 的属性名称。
例如,class 变成了 className,而 tabindex 则对应着 tabIndex

JSX 防注入攻击:会自动过滤

JSX 代表 Objects

Babel 转译器会把 JSX 转换成一个名为 React.createElement() 的方法调用。

const element = (
  

Hello, world!

);

等同于

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

返回

const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world'
  }
};

组件&Props

React 元素都是immutable 不可变的。当元素被创建之后,你是无法改变其内容或属性的。一个元素就好像是动画里的一帧,它代表应用界面在某一时间点的样子。

根据我们现阶段了解的有关 React 知识,更新界面的唯一办法是创建一个新的元素,然后将它传入 ReactDOM.render() 方法:

function tick() {
  const element = (
    

Hello, world!

It is {new Date().toLocaleTimeString()}.

); ReactDOM.render(element, document.getElementById('root')); } setInterval(tick, 1000);

React 只会更新必要的部分

React DOM 首先会比较元素内容先后的不同,而在渲染过程中只会更新改变了的部分。
定义组件的两种方式:

函数定义:
function Welcome(props) {
  return 

Hello, {props.name}

; }
类定义:
class Welcome extends React.Component {
  render() {
    return 

Hello, {this.props.name}

; } }

调用:

const element = ;

在函数定义:props. 可以直接访问,而在类中需要this.props.

Props的只读性

props是单向数据流,在组件里不能修改。

State & 生命周期

定义为类的组件有一些额外的特性。局部状态就是如此:只能用于类的一个功能。
这样我们就可以定义一个状态:状态与属性十分相似,但是状态是私有的,完全受控于当前组件。

这里可以理解为Vue里组件的data。



当count改变的时候,视图也会刷新,而这里就和react的state类型。

vue里的data是双向绑定的,但是react里不是

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      

Hello, world!

It is {this.state.date.toLocaleTimeString()}.

); } }

如何让时钟走起来?在生命周期函数中挂载方法:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      

Hello, world!

It is {this.state.date.toLocaleTimeString()}.

); } }
关于setState()需要注意:
  1. 不能直接更新状态
// Wrong
this.state.comment = 'Hello';
  1. 状态更新是异步的
// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});
// Correct
this.setState(function(prevState, props) {
  return {
    counter: prevState.counter + props.increment
  };
});
  1. 可以单独设置状态的某一个属性 而不是整个对象:
  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }

事件处理:

  • React事件绑定属性的命名采用驼峰式写法,而不是小写。
  • 如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM元素的写法)

在 React 中另一个不同是你不能使用返回 false 的方式阻止默认行为。你必须明确的使用 preventDefault。

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    
      Click me
    
  );
}

你必须谨慎对待 JSX 回调函数中的 this,类的方法默认是不会绑定 this 的。如果你忘记绑定 this.handleClick 并把它传入 onClick, 当你调用这个函数的时候 this 的值会是 undefined

constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    this.handleClick = this.handleClick.bind(this);
  }

这并不是 React 的特殊行为;它是函数如何在 JavaScript 中运行的一部分。通常情况下,如果你没有在方法后面添加 () ,例如 onClick={this.handleClick},你应该为这个方法绑定 this

如果使用 bind 让你很烦,这里有两种方式可以解决。如果你正在使用实验性的属性初始化器语法,你可以使用属性初始化器来正确的绑定回调函数:

class LoggingButton extends React.Component {
  // This syntax ensures `this` is bound within handleClick.
  // Warning: this is *experimental* syntax.
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      
    );
  }
}

如果没有属性初始化器语法:

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // This syntax ensures `this` is bound within handleClick
    return (
      
    );
  }
}

条件渲染:

if-else:
render() {
    const isLoggedIn = this.state.isLoggedIn;

    let button = null;
    if (isLoggedIn) {
      button = ;
    } else {
      button = ;
    }

    return (
      
{button}
); }
与运算符 && 和三目运算符:
function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    

Hello!

{unreadMessages.length > 0 &&

You have {unreadMessages.length} unread messages.

}
); }
render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    
{isLoggedIn ? ( ) : ( )}
); }

if-else是语法不是表达式,{}可以填入任何表达式。所以可以用运算符&&,这点和vue也是一样的。但是需要注意的是&&前必须是Boolean类型不能类Boolean类型,比如0,空字符串''

如何阻止组件渲染?

在极少数情况下,你可能希望隐藏组件,即使它被其他组件渲染。让 render 方法返回 null 而不是它的渲染结果即可实现。

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return (
    
Warning!
); }

组件的 render 方法返回 null 并不会影响该组件生命周期方法的回调。例如,componentWillUpdate 和 componentDidUpdate 依然可以被调用。

列表 & Keys

渲染多个组件:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  
  • {number}
  • );

    我们把整个listItems插入到ul元素中,然后渲染进DOM:

    ReactDOM.render(
      
      {listItems}
    , document.getElementById('root') );

    当我们运行这段代码,将会看到一个警告 a key should be provided for list items ,意思是当你创建一个元素时,必须包括一个特殊的 key 属性。

    Keys

    Keys可以在DOM中的某些元素被增加或删除的时候帮助React识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。

    熟悉Vue这里就能直接理解

    const numbers = [1, 2, 3, 4, 5];
    const listItems = numbers.map((number) =>
      
  • {number}
  • );

    表单:

    受控组件:在HTML当中,像,