JavaScript 和 React,React用了大量语法糖,让JS编写更方便。


https://reactjs.org/docs/higher-order-components.htmlhttps://codepen.io/gaearon/pen/WooRWa?editors=0010

JSX in Depth

https://babeljs.io/  JS编译器,学习react和JS直接的转换。

 JSX仅支持句法糖syntactic sugar:

React.createElement(component, props, ...children)函数,

JSX code:

<MyButton color="blue" shadowSize={2}>
 Click Me
</MyButton> 

 编译compiles into:

React.createElement(

  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)   

也可以使用self_closing form of the tag if there are no children. So:

<div className="sidebar" />

compiles into:

React.createElement(
  'div',
  {className: 'sidebar'},
  null
)

函数形式的:

function hello() {

  return <div>Hello world!</div>; 

转换为:

function hello() {
  return React.createElement(
    'div',
    null,
    'Hello world!'
  );
}

关于React元素的格式: 

React 一定在Scope内。

使用. Dot Notaiton ,可以在JSX中使用点符号。如果一个模块要调出一些React组件,这样就方便了。例子:

import React from 'react';
const MyComponents = {
  DatePicker: function DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
  }
}
function BlueDatePicker() {
  return <MyComponents.DatePicker color="blue" />;
}

自定义的组件必须首字母大写(除非分配它一个首字母大写的变量)。function Hello(props){...} 

在运行时选择类型Choosing the type at runtime 

不能把表达式用做React element type。但是可以把它分配给一个大写字母的变量,然后就可以间接用JSX格式了

import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
  photo: PhotoStory,
  video: VideoStory
};
function Story(props) {
  // Wrong! JSX type can't be an expression.
  return <components[props.storyType] story={props.story} />;
}
function Story(props) {
  // Correct! JSX type can be a capitalized variable.
  const SpecificStory = components[props.storyType];
  return <SpecificStory story={props.story} />;
}

 Props in JSX

通过{}, 任何JS expression 都可以作为props. 例如<MyComponent foo={1 + 2 + 3 + 4} />

if statements and for loops 不是JS表达式,不能直接用于JSX。但{}就能用了

function NumberDescriber(props) {
  let description;
  if (props.number % 2 == 0) {
    description = <strong>even</strong>;
      } else {
        description = <i>odd</i>
      }
  return <div>{props.number} is an {description} number</div>;
}

条件判断 Inline的写法: 

{true && expression}  //如果是true,则执行表达式。 

{condition ? true : false }

防止组件被渲染:

return null; ⚠️,组件的lifecycle 方法钩子方法,仍然生效componentWillUpdate 和 componentDidUpdate。


Children in JSX

string Literals

<div>This is valid HTML &amp; JSX at the same time.</div>

&amp; 就是& 

编译:

React.createElement(
  "div",
  null,
  "This is valid HTML & JSX at the same time."
);

JSX移除一行开头和结尾的空格

JSX Children

支持内嵌JSX元素作为孩子。在嵌套组件中很有用。

React组件也返回数组元素。return [, ,]; 

JS expression也可以作为孩子。

function Item(props) {
  return <li>hello, {props.message}</li>;  //props.children
}
function TodoList() {
  const todos = ['finish', 'submit ', 'review'];
  return (
    <ul>

//这个是函数作为props.children。 

      {todos.map(message =>
        <Item key={message} message={message} />
      )} 
    </ul>
  );
}

Function as Children 

 见标黄的代码.React.createElement(component, props,...child)

function Repeat(props) {
  let items = [];
  for (let i= 0; i < props.numTimes; i++) {
    items.push(props.children(i));
  }
  return <div>{items}</div>;
}
function ListOfTenThings() {
  return (
    <Repeat numTimes={10}>
      {(index) => <div key={index}>{index}:This is item {index}</div>}
    </Repeat>
  );
}

 

Booleans, Null, and Undefined are Ignored. 

false ,null, undefined, true都是验证的孩子,不过它们不渲染。

所以可以作为条件判断 condition && expression。

如果showHeader是true则渲染<Header />

<div>
  {showHeader && <Header />}
  <Content />
</div>

⚠️ 0会被渲染

如果要让true渲染使用类型转换,String()。 


Typechecking With PropTypes(未看)

用于检查输入的一个方法PropTypes ,这是React内置的方法,JS扩展中也有Flow,TypeScript等扩展插件。

大型的代码检查,官方推荐使用Flow or TypeScript 而不是用默认的。 

https://reactjs.org/docs/typechecking-with-proptypes.html 

PropTypes输出了一组验证器用于确保你接收的数据是通过验证的。如果一个未通过验证的值提供给一个prop,一条warning会显示在JS console中。propTypes只用于开发模式。

import PropTypes from 'prop-types';
class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}
Greeting.propTypes = {
  name: PropTypes.string    //确保是string类的值,否则报告⚠️信息。
};

Refs ans the DOM(未看)

https://reactjs.org/docs/refs-and-the-dom.html 

在典型的数据流模式,组件之间的交互使用props。但有少数情况属于例外情况。

Refs提供了一个方法,能够使用DOM nodes 和React elements created in the render method。React提供了这个escape hatch逃生舱门。

何时用:

  • 管理focus,text selection ,media playback
  • 合并第三方DOM库
  • 打开必要的动画Triggering imperative animations 
React.createRef:

创建一个ref可以附加到React elements 

this.myRef = React.createRef() 并通过ref属性付给React元素


Uncontrolled Components 

推荐使用controlled components 来实现forms, 这时,表格数据被React组件处理。

但我们也可以用别的方式,这时,表格data被DOM自身处理。 

既然非控制组件保持了DOM的原生性,有时它比较容易合并React和非React代码。如果你想要更快并不在乎代码太脏(可读性差),也能够稍微少输入点代码。

你应该尽量用可控制的组件。

 https://codepen.io/gaearon/pen/WooRWa?editors=0010

 红字是用原生DOM加ref。

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleTextChange = this.handleTextChange.bind(this);
    this.state = {text: ""};
  }
  
  handleTextChange(e) {
    this.setState({text: e.target.value});
  }
  
  handleSubmit(e) {
    // alert("A name was submitted: " + this.input.value);
    alert("A name was submitted: " +  this.state.text);
    e.preventDefault();
  }
  
  render() {
    return (
      // <form onSubmit={this.handleSubmit}>
      //   <label>
      //     Name:
      //     <input type="text" ref={(input) => this.input = input}  />
      //   </label>
      //   <input type="submit" value="Submit" />
      // </form>
      <form>
        <label>
          Name:
          <input type="text" onChange={this.handleTextChange}/>
        </label>
        <input type="submit" value="Submit" onClick={this.handleSubmit} />
      </form>
    );
  }
}
ReactDOM.render(
  <NameForm />,
  document.getElementById('example')
);

Optimizing Performance(略读)

优化执行的方法和工具。

使用React Developer Tools for Chrome.(也有其他浏览器版本) 

这个工具可以制作Timeline可视化每个组件mount update, unmount. 


Context(一个不使用传统方法传递数据的方法。)

https://reactjs.org/docs/context.html 

一整章节,暂时不看。


 Fragments

让你返回多个元素在一个render()方法中,不需要创建一个额外的DOM 元素。

The React.Fragment component lets you return multiple elements in a render()method without creating an additional DOM element:
render() {
  return (
    <React.Fragment>
      <ChildA />
      <ChildB />
      <ChildC />
    </React.Fragment>
  );
}

这时如果是静态的可以不加key,最好加上。另外用[]也可以,但必须加key

 HTML description list:

<dl>

  <dt>

    <dd></dd>

  </dt> 

</dl> 


Portals

大门,入口。 

https://reactjs.org/docs/portals.html 

渲染孩子进入一个Dom节点 

ReactDOM.createPortal(child,container) 

第一个参数是任意的渲染的React child。如an element, string, or fragment. 

第二个参数container是一个DOM元素。 

一般来说,从一个组件的渲染方法中返回一个元素,它作为孩子附加在离它最近的父节点后。

而使用createPortal这样就可以插入一个孩子到DOM中不同的位置。 (但仍然受到父组件event事件的影响)

 案例:https://codepen.io/gaearon/pen/yzMaBd?editors

    return (
      <div className="app">
        This div has overflow: hidden.
        <button onClick={this.handleShow}>Show modal</button>
        {modal}  //看似是在这个block中,其实Modal组件使用了createProtal()把自己插入到了其他DOM节点。
      </div>
    );

Event Bubbling Through Portals

a portal可以插入到在DOM tree的任何位置,不过它在其他方面仍旧是一个普通的React child。

假如:在一个父组件中渲染一个子组件(Modal),那么Modal就可以被这个父组件捕捉到。这个父组件不会考虑Modal是否用了protals。

即便Modal用了protal把代码插入到不属于父组件的其他节点,父组件仍然可以捕捉到Modal,父组件定义了一个点击事件,对Modal中的元素进行点击也会触发父组件的点击事件。

案例:https://codepen.io/chentianwei411/pen/ZoLeBE?editors=0010 


Error Boundaries 

错误边界。 目的:解决仅仅是部分UI的错误就会造成整个app崩溃的问题。

Error boundaries也是一个React组件。JS 错误发生在子组件的任何位置,它都可以捕捉到,并且log those errors, 并且display a fallback UI。

Error boundaries 捕捉错误是在渲染的时候,因此lifecycle methods 和 constructors of the whole tree都低于Error boundaries.

⚠️以下超出了Error-b的使用范围:

Event handlers, 异步代码, 服务器端渲染, 自身抛出错误。


Higher-Order Components (基本用法,一些约定没有看。)

一种代码的抽象化, 根据dry原则,把有相同逻辑的组件重构。

即重构一个函数,这个函数接受一个组件并return 一个新组件。 

要点:发现有很多相同逻辑(内部代码基本一样)的组件, 为了减少代码的量和便于阅读维护。

 https://reactjs.org/docs/higher-order-components.html

 // 调用Highter-Order组件withSubscription.把返回的新组件存入一个JSX.

const CommentListWithSubscription = withSubscription(

  CommentList,

  (DataSource) => DataSource.getComments() 

); 

const BlogPostWithSubscription = withSubscription(
  BlogPost,
  (DataSource, props) => DataSource.getBlogPost(props.id)
);

function withSubscription(WrappedComponent,  selectData) {

  //WrappedComponent是组件名字, selectData是数据及其使用的methods。 

  return class extends React.Component {...} ;  //class后面没有组件名字

⚠️ ,不要在higher-order组件中对原有组件修改,如果需要组件进行功能的变化,把这个变化写在return中。

⚠️, 约定convension: 传递不相关的props,通过wrapped 组件。 在render方法中使用不相关的props.


Render Props

术语render prop是一个简单的技术:在React组件之间,通过使用一个值是函数的prop来分享代码。

The term "render prop" refers to a simple technique for sharing code between React components using a prop whose value is a function. 

<DataProvider render={data => (
  <h1>Hello {data.target}</h1>
)}/>

一个组件带着一个render prop,这个组件渲染的时候可以使用这个render prop的值

a render prop is a function prop that a component uses to know what to render.

 https://reactjs.org/docs/render-props.html


 


React.Component 

组件的lifecycle methods

Methods prefixed with will are called right before sth happens. did are called after sth happens. 

Mounting

这些方法在一个组件实例被创建和插入DOM时调用。 

constructor(props){...}   //在加载组件前调用。

before it is mounted,如果组件是一个子类,还需要在其他声明前面调用super(props)。 constructor()用于初始化state。也用于bind event-handlers to the class instance.

分配给this.state的对象可以包含props。但⚠️这不是时时更新的,最好不这么用,例子: 

  this.state = {
    color: props.initialColor
  };


UNSAFE_componentWillMount()   //在加载组件前引用。它在render()前调用。

render() 

When called, it should examine this.props and this.state and return one of the following types:

  • React elements. 包括自定义的组件或原生的DOM component <div />
  • String and numbers. 作为text nodes 渲染在DOM中。
  • Portals. Created with ReactDOM.createPortal 
  • null 什么也不加载
  • Booleans。一般用于 return test && <Child />模式,当test是true时,加载后面
⚠️ shouldComponentUpdate()方法返回false时,不加载render()

componentDidMount()   //在组件加载后立即引用

用途:

加载远程endpoint的数据,这里可以实例化network request。

也可以建立任何订阅并配合componentWillUnmount()取消订阅。 

调用setState(),会激活额外的rendering. 

Updating

 一个update会被props或state的改变引起。下面的方法当一个组件被再加载时调用。(只看了其中几个,一共7个方法)

componentWillReceiveProps() 

在一个已经加载的组件再次接收新的props之前引用这个方法。 这个方法限制很多不推荐用。

shouldComponentUpdate(nextProps, nextState)

返回true,false。让React知道一个组件的输出是否被当前state or propsde 变化所影响。如果是true,则组件再render()。方法默认是true。所以一般不主动使用这个方法。 

如果是false,render(), componentWillUpdate(), componentDidUpdate()不会调用。

componentWillUpdate(nextProps, nextSate)

当一个新props or state 被接收到后,在渲染之前引用。

render() 

每次更新props or state后,调用render(). 

componentDidUpdate(prevProps, prevState, snapshot) 

在更新发生后,立即引用。

Unmounting

  • componentWillUnmount(): 在一个组件被卸载和删除前立即引用。用于执行必要的清洁。如未验证的timers, 取消网络请求, 清洁任何在componentDidMount()中的订阅
Error Handing
  •  componentDidCatch():这个方法被调用当一个❌发生在渲染中,在lifecyle方法中,或者在一个孩子组件的constructor中。

Other APIS

setState()

enqueuqs changes to the component state and tells React that this component and its children need to be re-rendered with the updated state.

改变组件的状态state并告诉React“组件和它的孩子需要根据更新的state再渲染”

这是一个主要的方法,用来更新user interface in response,事件处理和服务器响应。

把setState()当作一个request,而不是更新组件的即时命令。 

setState()不总是立即执行更新组件,因为它类似request,有延迟。因此,使用componentDidUpdate或者setState(updater, callback)可以保证fire(立即执行).


setState(updater, callback)

updater是一个函数:(prevState, props) => stateChange   //prevState是之前state的一个引用。 例子:用props.step增加一个值到state中。

this.setState((prevState, props) => {
  return {counter: prevState.counter + props.step};
}); 

callback参数是可选的函数。在setState完成更新,组件被再渲染后执行这个函数,推荐使用componentDidUpdate代替。 

第一个参数可以是一个对象object.代替一个函数。 这个执行会把状态变化合并到新状态中。 

this.setState({quantity: 2}) 

forceUpdate() 

component.forceUpdate(callback),如果render()方法依靠其他数据源,你可以告诉组件调用forceUpdate()来再渲染。个人理解:这个方法就是用来执行渲染的。

Class Properties

defaultProps

给组件的property设定默认值。 

class CustomButton extends React.Component {
  // ...
}
CustomButton.defaultProps = {
  color: 'blue'
};

渲染的时候自动增加上color="blue"

render() {
  return <CustomButton /> ; // props.color will be set to blue
}

 displayName 

 https://reactjs.org/docs/higher-order-components.html#convention-wrap-the-display-name-for-easy-debugging

debug用。

Instance Properties

  • props
  • state 


ReactDOM 

import ReactDOM from 'react-dom'

react-dom package提供了DOM-specific methods。大多数组件不需要使用这个module.

ReactDOM.render(element, container[, callback]) 

渲染一个React element到DOM中。具体位置是container, 返回a reference 给组件。

如果之前已经渲染进container中,更新时只修改必要的部分。

callback可选,在组件渲染或更新后执行.

createPoratal() 

ReactDOM.createPortal(child, container) 


hydrate()
unmountComponentAtNode()
findDOMNode()

ReactDOMServe

import ReactDOMServer from 'react-dom/server'; 

用于把组件渲染到静态标记中,一般用于一个Node server

这两个方法可以用于server,也可以用在浏览器。 

renderToString()

renderToStaticMarkup() 

ReactDOMServer.renderToString(element) 

渲染一个React元素到 原始HTml. React返回一个HTML string。


DOM Elements

https://reactjs.org/docs/dom-elements.html 

style 

style属性可以接受JS 对象。属性要用驼峰写法。如backgroundImage. px可以省略

const divStyle = {
  color: 'blue',
  background: 'lightblue',
};
function Hello() {
  return <div style={divStyle}>Hello World!</div>;
}

value 

<input>, <textarea>组件支持value属性。

className 

用来指定css class的名字。

checked 

<input>组件中的type类型为checkbox or radio的支持这个属性。 

All Supported HTML Attributes 


SyntheticEvent 

人工事件

event handlers被传到人工事件的实例,一个跨浏览器的包裹器(包含浏览器的原生事件)。

每个SyntheticEvent对象有一系列的属性attributes:如:

currentTarget, target, type, timeStamp, isTrusted, preventDefault()等等。 

 https://reactjs.org/docs/events.html

原文地址:https://www.cnblogs.com/chentianwei/p/8960912.html