[干货]一篇笔记入门React

我的笔记, 转载请注明html

转载自 szhshp的第三边境研究所react

Refs and the DOM

In the typical React dataflow, props are the only way that parent components interact with their children. To modify a child, you re-render it with new props. However, there are a few cases where you need to imperatively modify a child outside of the typical dataflow. The child to be modified could be an instance of a React component, or it could be a DOM element. For both of these cases, React provides an escape hatch.git

通常状况下想要刷新child elem必须经过新的prop刷新, 可是其实能够有另外一个方法, 就是使用refgithub

When to Use Refs

There are a few good use cases for refs:express

  • Managing focus, text selection, or media playback.
  • Triggering imperative animations.
  • Integrating with third-party DOM libraries.

Avoid using refs for anything that can be done declaratively.api

For example, instead of exposing open() and close()methods on a Dialog component, pass an isOpen prop to it.数组

使用ref以前切记要肯定一下对应的属性是否是可使用prop代替, 开发时应该尽量听从React推荐的信息流闭包

Adding a Ref to a DOM Element

React supports a special attribute that you can attach to any component. The ref attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted.app

关于ref有这些特色:less

  1. 能够给任何DOM提供这个attr
  2. 提供给ref的value应该是个callback
  3. 这个callback能够在mounted/unmounted的时候调用
  • 注意会在mounted/unmounted的时候执行一次, 而不是每次渲染的时候执行
  1. 当提供这个参数给HTML elem的时候, 这个ref指向的callback会获取当前DOM elem做为参数.

例子:

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.focusTextInput = this.focusTextInput.bind(this);
  }

  focusTextInput() {
    // Explicitly focus the text input using the raw DOM API
    // 3. 所以这儿能够经过this.textInput调用focus()方法
    this.textInput.focus();
  }

  render() {
  
    // Use the `ref` callback to store a reference to the text input DOM
    // element in an instance field (for example, this.textInput).
    // 1. Component载入的时候就会执行ref里面的callback.
    // 2. 而后这个Elem会当作参数传入, 所以就能够经过this.textInput引用这个DOM elem
    
    
    return (
      <div>
        <input
          type="text"
          ref={(input) => { this.textInput = input; }} />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

Adding a Ref to a Class Component

相似ref在HTML DOM中的使用, 将ref赋值给自定义Component的时候, ref对应的callback就会接受自身这个instance做为参数

注意: 必需要这个自定义Component是个完整的class, 不能够是函数

When the ref attribute is used on a custom component declared as a class, the ref callback receives the mounted instance of the component as its argument. For example, if we wanted to wrap the CustomTextInput above to simulate it being clicked immediately after mounting:

class AutoFocusTextInput extends React.Component {
  componentDidMount() {
    // 2. 这儿就能够对这个instance进行引用
    this.textInput.focusTextInput();
  }

  render() {
    return (
      <CustomTextInput
      // 1. 对于自定义的Component, ref对应的callback会将自身这个instance当作参数传进去
        ref={(input) => { this.textInput = input; }} />
    );
  }
}

Exposing DOM Refs to Parent Components

通常数据流不该该在Parent Class里面控制Child Class, 可是偶尔就有这样傻逼的需求.

这时候用ref最适合了, 可是依然不推荐这么使用.

更好的解决办法是你和需求分析的人打一架而后让他根据代码改需求

固然上文提到了解决办法是让child class暴露一个prop, 可是这个办法没法对function Component使用.

另外下面这个办法对function Component也有用:

function CustomTextInput(props) {
  // 2. 在child component里面将这个callback赋值给ref
  // 2+. 固然这儿只能用ref这个attr
  // 3. 而后这个child component在mount/unmount的时候就会执行这个callback
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

class Parent extends React.Component {
  render() {
  // `Parent` passes its ref callback as an `inputRef`prop to the `CustomTextInput`
  // 1. 这儿提供一个callback做为props.inputReg
    return (
      <CustomTextInput
        inputRef={el => this.inputElement = el}
      />
    );
  }
}

最终在parent component中就能够经过inputElement这个变量调用到对应输入框元素.

并且这个能够逐级传递, 好比下面这个隔代传递的例子:

function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

function Parent(props) {
  return (
    <div>
      My input: <CustomTextInput inputRef={props.inputRef} />
    </div>    
  );
}

class Grandparent extends React.Component {
  render() {
    return (
      <Parent
        inputRef={el => this.inputElement = el}
      />
    );
  }
}

看起来暴露DOM有些别扭, 可是不少时候需求就是比较特别. 所以上面是推荐用法.

旧版本React里面曾经有过使用this.refs.textInput的用法, 其中ref会指向一段字符串, 新版本React不推荐如此使用

注意事项

若是ref是个inline function, updates的时候会被调用两次. 第一次是null而后第二次是DOM Elem.

这个是由于update的时候React须要清理旧的而且创建新的component

Solutions

为了防止这个问题, 能够将ref callback和对应class进行绑定.

即便不绑定也不会引起太多问题

JSX In Depth

JSX将经过Babel进行编译.

标准首位标签格式

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

compiles into:

React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)

自闭合标签格式

You can also use the self-closing form of the tag if there are no children. So:

<div className="sidebar" />

compiles into:

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

Specifying The React Element Type

通常Component使用大写字母开头, 若是在当前JSX里面使用<XXX/>那么XXX这个Component就必须出如今Scope以内.

另外可使用import语句将Component引用到Scope内

Using Dot Notation for JSX Type

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" />; 
}

User-Defined Components Must Be Capitalized

自定义Component(好比 <MyComponent/>)应该大写字母开头
系统自带的Component(好比 <div/>)应该小写字母开头

不然系统会抛出警告

Choosing the Type at Runtime

注意JSX Obj的tags必须是完整的单词, 若是想要动态生成tag名称能够用赋值的办法

错误的例子:

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} />;
}

Prop in JSX

JavaScript Expressions as Props

关于使用JS表达式做为prop:

<MyComponent foo={1 + 2 + 3 + 4} />

If condition within JSX

不可以直接使用, 可是能够用这个替代方法:

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

另一个很实用的条件判断的snippet

This can be useful to conditionally render React elements. This JSX only renders a <Header /> if showHeader is true:

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

### String Literals


When you pass a string literal, its value is HTML-unescaped. So these two JSX expressions are equivalent:



<MyComponent message="<3" />

<MyComponent message={'<3'} />

### Props Default to “True”


If you pass no value for a prop, it defaults to true. These two JSX expressions are equivalent:

<MyTextBox autocomplete />

<MyTextBox autocomplete={true} />

### Spread Attributes


If you already have `props` as an object, and you want to pass it in JSX, you can use `...` as a “spread” operator to pass the whole props object. These two components are equivalent:

>提供Props时, 如有一个Obj而且这个Obj里面全部Attr和须要的Prop相匹配, 那么可使用`spread` operator 进行赋值


function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}

function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}

另外对于`spread` operator也能够给部分值赋值:



const Button = props => {

//将传进函数里面的props.kind 赋值给kind, 将其余属性赋值给...other
const { kind, ...other } = props;

const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
//而后将...other传给button这个elem, 而没有传递kind这个参数
return <button className={className} {...other} />;
};

const App = () => {
return (
<div>
<Button kind="primary" onClick={() => console.log("clicked!")}>
Hello World!
</Button>
</div>
);
};

> # 关于解构运算符
>
>MDN参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
>
这玩意是ES6新引进的运算符, 经过三个点进行引用`...`
>
> ```
>function sum(x,y,z){
  return x+y+z
}
>
console.log(sum(...[1,2,3])) //6
console.log(sum(...[1,2,3,4,5])) //6
console.log(sum(...[1,,3,4,5])) //NaN
>
var doSomething = function(...args){
  return sum(..args)
}
>
console.log(doSomething(...[1,2,3])) //6
>
//对Object是否有效呢?
var obj = { a:"A", b:"B", c:"C", d:"D", e:"E" }
var {a,b,...others} = obj //报错var {a,b,...others} = obj //报错

在老版本ES6中, 对Obj进行解构赋值会报错, 可是JSX中容许这样的使用.

Children in JSX

子元素所有会经过props.children进行引用.

另外若是没有子tag而只是放置了一段文本, 那么props.children就会是tag之间的一段字符串

Hint: HTML is unescaped!

<MyComponent>Hello world!</MyComponent>

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


tags之间的空格和空行都会被忽略.

<div>

  Hello World
</div>

另外也能够将JS表达式用于child elem. 好比一个很典型的使用数组循环生成列表的例子:

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

Functions as Children

反正只要最后返回的是一个完整的JSX Obj便可

// 2. 咱们在渲染parent elem
function Repeat(props) {
  let items = [];
  for (let i = 0; i < props.numTimes; i++) {
    // 3. 经过调用child elem对应的函数生成jsx obj
    items.push(props.children(i));
  }
  return <div>{items}</div>;
}

// 1. 返回的JSX obj的child elem是个函数
function ListOfTenThings() {
  return (
    <Repeat numTimes={10}>
      {(index) => <div key={index}>This is item {index} in the list</div>}
    </Repeat>
  );
}

Booleans, Null, and Undefined Are Ignored

false, null, undefined, and true are valid children. They simply don’t render. These JSX expressions will all render to the same thing:

<div />

<div></div>

<div>{false}</div>

<div>{null}</div>

<div>{undefined}</div>

<div>{true}</div>

Thinking in React

就是React项目流程的rethinking

Step 1: Break The UI Into A Component Hierarchy

  1. draw boxes around every component (and subcomponent) in the mock and give them all names
  • 使用一些规则(好比单一原则)判断元素应该属于哪些部分

[图片上传失败...(image-af5c7e-1512723756201)]

  1. 获得Component层次列表
  2. 决定数据模型

Step 2: Build A Static Version in React

  1. 先写个静态的
  • 重用的Component要准备好
  • 静态的部分应该不须要用到任何State, State应该仅仅用于动态的Component
  • 从上往下或者从下往上创建均可以, 小型项目从上往下会快一些, 大型项目反之
  1. 改成动态模型
  • 通常最大的那个Component会接受数据做为所有数据源

Step 3: Identify The Minimal (but complete) Representation Of UI State

  1. 创建项目的时候, 最好能先肯定minimal set of mutable state, 也就是最小动态模块
  2. 判断一下动态模块是否能够设置成state

以前提到过的三个原则进行判断:

  1. Is it passed in from a parent via props? If so, it probably isn’t state.
  2. Does it remain unchanged over time? If so, it probably isn’t state.
  3. Can you compute it based on any other state or props in your component? If so, it isn’t state.

Step 4: Identify Where Your State Should Live

  1. 决定哪些Component应该拥有这些State, 哪些Component应该让State进行变化

React从头至尾就只有一条数据流有这些须要注意的:

  1. 能够经过自身State进行render的Component
  2. 最大的那个Component应该拥有State, 用于流程管理之类的业务, 这个State可能包含全部动态成分的内容
  3. 若是没法找到一个值得拥有一个State的Component, 那就写个新的, 可能能够放在最大的State的更上一层

Step 5: Add Inverse Data Flow

就是数据的各类交互呗

一个重要的概念:

有些时候parent class可能会给child class提供一个eventHandler()

这玩意能够当作一种callback, 赋值给child class的onchange, child class经过调用这个onChange使得parent class的state变化.

若是只有一个值的状况下甚至能够不用给child class设置任何的state# React: 关于setState()

React&Error: setState()不马上响应到DOM, 老是慢一步

这个八成是由于在setState的同一个方法里面调用了this.state

这时候获取到的state都是前一个state

下方是参考文献:


原文: https://medium.com/@mweststra...
做者: Michel Weststrate

前言

这篇文章原标题是3 Reasons why I stopped using React.setState,可是我对原文做者提出的论点不是很感冒,可是做者提出的三点对React新手来讲是很容易忽略的地方,因此我在这里只提出部份内容,并且把标题改成使用React.setState须要注意的三点。

正文

对React新手来讲,使用setState是一件很复杂的事情。即便是熟练的React开发,也颇有可能由于React的一些机制而产生一些bug,好比下面这个例子:

文档中也说明了当使用setState的时候,须要注意什么问题:

注意:
绝对不要 直接改变this.state,由于以后调用setState()可能会替换掉你作的改变。把this.state当作是不可变的。

setState()不会马上改变this.state,而是建立一个即将处理的state转变。在调用该方法以后访问this.state可能会返回现有的值。

对setState的调用没有任何同步性的保证,而且调用可能会为了性能收益批量执行。

setState()将老是触发一次重绘,除非在shouldComponentUpdate()中实现了条件渲染逻辑。若是可变对象被使用了,但又不能在shouldComponentUpdate()中实现这种逻辑,仅在新state和以前的state存在差别的时候调用setState()能够避免没必要要的从新渲染。

总结出来,当使用setState的时候,有三个问题须要注意:

1. setState是异步的(译者注:不保证同步的)

不少开发刚开始没有注意到setState是异步的。若是你修改一些state,而后直接查看它,你会看到以前的state。这是setState中最容易出错的地方。 setState这个词看起来并不像是异步的,因此若是你不假思索的用它,可能会形成bugs。下面这个例子很好的展现了这个问题:

class Select extends React.Component {
  constructor(props, context) {
    super(props, context)
    this.state = {
      selection: props.values[0]
    };
  }

  render() {
    return (
      <ul onKeyDown={this.onKeyDown} tabIndex={0}>
        {this.props.values.map(value =>
          <li
            className={value === this.state.selection ? 'selected' : ''}
            key={value}
            onClick={() => this.onSelect(value)}
          >
            {value}
          </li> 
        )}  
      </ul>
    )
  }

  onSelect(value) {
    this.setState({
      selection: value
    })
    this.fireOnSelect()
  }

  onKeyDown = (e) => {
    const {values} = this.props
    const idx = values.indexOf(this.state.selection)
    if (e.keyCode === 38 && idx > 0) { /* up */
      this.setState({
        selection: values[idx - 1]
      })
    } else if (e.keyCode === 40 && idx < values.length -1) { /* down */
      this.setState({
        selection: values[idx + 1]
      })  
    }
    this.fireOnSelect()
  }

  fireOnSelect() {
    if (typeof this.props.onSelect === "function")
      this.props.onSelect(this.state.selection) /* not what you expected..*/
  }
}

ReactDOM.render(
  <Select 
    values={["State.", "Should.", "Be.", "Synchronous."]} 
    onSelect={value => console.log(value)}
  />,
  document.getElementById("app")
)

第一眼看上去,这个代码彷佛没有什么问题。两个事件处理中调用onSelect方法。可是,这个Select组件中有一个bug很好的展示了以前的GIF图。onSelect方法永远传递的是以前的state.selection值,由于当fireOnSelect调用的时候,setState尚未完成它的工做。我认为React至少要把setState更名为scheduleState或者把回掉函数设为必须参数。

这个bug很容易修改,最难的地方在于你要知道有这个问题。

2. setState会形成没必要要的渲染

setState形成的第二个问题是:每次调用都会形成从新渲染。不少时候,这些从新渲染是没必要要的。你能够用React performance tools中的printWasted来查看何时会发生没必要要渲染。可是,大概的说,没必要要的渲染有如下几个缘由:

  • 新的state其实和以前的是同样的。这个问题一般能够经过shouldComponentUpdate来解决。也能够用pure render或者其余的库来解决这个问题。

  • 一般发生改变的state是和渲染有关的,可是也有例外。好比,有些数据是根据某些状态来显示的。

  • 第三,有些state和渲染一点关系都没有。有一些state多是和事件、timer ID有关的。

3.setState并不能颇有效的管理全部的组件状态

基于上面的最后一条,并非全部的组件状态都应该用setState来进行保存和更新的。复杂的组件可能会有各类各样的状态须要管理。用setState来管理这些状态不但会形成不少不须要的从新渲染,也会形成相关的生命周期钩子一直被调用,从而形成不少奇怪的问题。

后话

在原文中做者推荐了一个叫作MobX的库来管理部分状态,我不是很感冒,因此我就不介绍。若是感兴趣的,能够经过最上面的连接看看原文中的介绍。

基于上面提出的三点,我认为新手应该注意的地方是:

setState是不保证同步的

setState是不保证同步的,是不保证同步的,是不保证同步的。重要的事情说三遍。之因此不说它是异步的,是由于setState在某些状况下也是同步更新的。能够参考这篇文章

若是须要在setState后直接获取修改后的值,那么有几个方案:

传入对应的参数,不经过this.state获取

针对于以前的例子,彻底能够在调用fireOnSelect的时候,传入须要的值。而不是在方法中在经过this.state来获取

使用回调函数

setState方法接收一个function做为回调函数。这个回掉函数会在setState完成之后直接调用,这样就能够获取最新的state。对于以前的例子,就能够这样:

this.setState({
  selection: value
}, this.fireOnSelect)

使用setTimeout

在setState使用setTimeout来让setState先完成之后再执行里面内容。这样子:

this.setState({
  selection: value
});

setTimeout(this.fireOnSelect, 0);

直接输出,回调函数,setTimeout对比

    componentDidMount(){
    this.setState({val: this.state.val + 1}, ()=>{
      console.log("In callback " + this.state.val);
    });

    console.log("Direct call " + this.state.val);   

    setTimeout(()=>{
      console.log("begin of setTimeout" + this.state.val);

       this.setState({val: this.state.val + 1}, ()=>{
          console.log("setTimeout setState callback " + this.state.val);
       });

      setTimeout(()=>{
        console.log("setTimeout of settimeout " + this.state.val);
      }, 0);

      console.log("end of setTimeout " + this.state.val);
    }, 0);
  }

若是val默认为0, 输入的结果是:

> Direct call 0
> In callback 1
> begin of setTimeout 1
> setTimeout setState callback 2
> end of setTimeout 2
> setTimeout of settimeout 2

和渲染无关的状态尽可能不要放在state中来管理

一般state中只来管理和渲染有关的状态,从而保证setState改变的状态都是和渲染有关的状态。这样子就能够避免没必要要的重复渲染。其余和渲染无关的状态,能够直接以属性的形式保存在组件中,在须要的时候调用和改变,不会形成渲染。或者参考原文中的MobX。

避免没必要要的修改,当state的值没有发生改变的时候,尽可能不要使用setState。虽然shouldComponentUpdate和PureComponent能够避免没必要要的重复渲染,可是仍是增长了一层shallowEqual的调用,形成多余的浪费。

以上

React: Form里面判断checkbox.md

handleStockedChange(e){
    var value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
  }

React: 关因而否应该将某个变量做为state.md

  1. Is it passed in from a parent via props? If so, it probably isn’t state.
  2. Does it remain unchanged over time? If so, it probably isn’t state.
  3. Can you compute it based on any other state or props in your component? If so, it isn’t state.# React&Error: Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null

八成就是return后面换行了, JS会自动加分号因此返回了undefined

React&Error: Unterminated JSX contents

这个八成就是写了两个elem或者某个elem没有闭合

Composition vs Inheritance

不推荐使用继承

我也不推荐

示例

Anything inside the <FancyBorder> JSX tag gets passed into the FancyBorder component as a children prop.

function FancyBorder(props) {
  return (
    <div className={'FancyBorder FancyBorder-' + props.color}>
      {props.children}
    </div>
  );
}


function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        Welcome
      </h1>
      <p className="Dialog-message">
        Thank you for visiting our spacecraft!
      </p>
    </FancyBorder>
  );
}

React: Form/Inputs

通常h5的input本身会管理本身的输入

Controlled Components

<span style="color: red;"> 实际上就是两点:</span>

  1. 给value绑定一个state的值, state.value最好
  2. 给onChange绑定一个事件, 修改state.value

React也能够在渲染的时候绑定事件, 事件里面就能够进行各类操做, 好比转换全部文本为uppercase之类的。另外修改了文本以后也能够马上反应/渲染到元素之上。

相似于将JS端的onChange放到了Server

  handleChange(event) {
    //经过变量event.target.value获取输入的值而且设置state
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>  //绑定onSubmit
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} /> //绑定onChange
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }

The textarea Tag

有一点和H5不一样的地方, React端的value的设置能够经过一个attr:

H5:

<textarea>
  Hello there, this is some text in a text area
</textarea>

React:

<textarea value={this.state.value} onChange={this.handleChange} />

The select Tag

设置selected的option的时候也略有不一样, 一样能够经过value这个attr设置

H5:

<select>
  <option value="grapefruit">Grapefruit</option>
  <option value="lime">Lime</option>
  <option selected value="coconut">Coconut</option>
  <option value="mango">Mango</option>
</select>

React:

 <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>

关于使用Value=Null来容许用户输入

能够看到, 将input的value设置为this.state.value就是为了阻止用户自由输入, 可是有些时候要将controlled Input的权限放开, 所以咱们能够将value设置为null或者undefined来开启用户自由输入.

ReactDOM.render(<input value="hi" />, mountNode);

// allow user input after 1sec
setTimeout(function() {
  ReactDOM.render(<input value={null} />, mountNode);
}, 1000);

关于Controlled Components 和 UnControlled Components

缩写成CC/UC

CC写起来其实挺麻烦, 由于每一个elem都要写个onChange.
其实也可使用UC

使用UC的例子:

  1. 使用一个ref将输入的值赋给多个参数, 好比this.xxx
  2. submit的时候对this.xxx进行各类validation以及处理
  handleSubmit(event) {
    alert('A name was submitted: ' + this.input.value);
    event.preventDefault();
  }

 render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" ref={(input) => this.input = input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }

React: 关于使用Keys来索引列表.md

通常将key放置到列表class里面进行赋值, 而不是放到item里面进行赋值

最好放在ul循环生成li的时候给li添加key

function ListItem(props) {
  const value = props.value;
  return (
  
    // Wrong! There is no need to specify the key here
    // 固然在这儿也得到不到key值
    <li key={value.toString()}>
      {value}
    </li>
    
  );
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
  
    // Wrong! The key should have been specified here:
    <ListItem value={number} />
    
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

正确用法:

function ListItem(props) {
  // Correct! There is no need to specify the key here:
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Correct! Key should be specified inside the array.
    <ListItem key={number.toString()}
              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

React: 关于render()里面隐藏一个元素.md

不要return一个JSX Obj, return null 便可

React: 关于使用Inline Expressions.md

If-then

return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&  //注意这里, 前面实际上是一个条件
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );

If-Else

  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
 return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );

React: Handling Events

几个要点:

  • React events are named using camelCase, rather than lowercase.
  • With JSX you pass a function as the event handler, rather than a string.

For example, the HTML:

<button onclick="activateLasers()">
  Activate Lasers
</button>

is slightly different in React:

<button onClick={activateLasers}>
  Activate Lasers
</button>

Another difference is that you cannot return false to prevent default behavior in React. You must call preventDefault explicitly.

防止默认事件的代码须要一些修正

<a href="#" onclick="console.log('The link was clicked.'); return false">
  Click me
</a>

In React, this could instead be:

function ActionLink() {
  function handleClick(e) {
    e.preventDefault(); // must be called implicitly 
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

When using React you should generally not need to call addEventListener to add listeners to a DOM element after it is created.

Instead, just provide a listener when the element is initially rendered.

初始化的时候给事件管理器,DOM初始化以后就别去添加其余监听器了。

JQuery: ...

示例

class Welcome extends React.Component{
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
    this.handleClick = this.handleClick.bind(this);  //绑定一下事件到this
  }

  handleClick() {
    console.log(123)
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render(){
    return (
      <div onClick={this.handleClick}>  //这里记得要写一个attr,而且要注意大小写
       {(this.state.isToggleOn)?'A':'B'}, {this.props.name}
      </div>
    );
  }
}

Passing Arguments to Event Handlers

下方的ID表明对应数据编号, 既可使用外部的循环Index.

这儿有点像是闭包

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

两种模式相似, 重点在于必定要将React event传进去

  1. 对于Arrow Function来讲, 须要显示传入
  2. 对于bind()来讲就不用了

来源: https://reactjs.org/docs/handling-events.html

React&Error: Cannot call a class as a function.md

class component看起来不能经过函数的方式进行调用
那么就改为tag模式调用就行:

  render(){
    return (
      <div>
      <WelcomeLList nameList={nameList}/>
      // {WelcomeList(this.props.nameList)} 
      // ↑↑ dont use this way if you created class component 
      </div>
    );
  }

React&Tips: 关于在Render里面使用变量.md

其实和Java的class同样,render里面能够直接调用prop参数了

class Root extends React.Component{
  constructor(props) {
    super(props);
  }

  render(){
    return (
      <div>
      {WelcomeList(this.props.nameList)}    //这里能够直接使用this.prop
      </div>
    );
  }
}

在React中使用数组做为参数

简单易懂,直接赋值一个数组便可,不用加双引号,否则会被当作长字符串

var nameList = ["Mike","Jack","Dick"];
ReactDOM.render(
  <Root nameList={nameList}/>,
  // <Root nameList="{nameList}"/>, // This is wrong
  document.getElementById('root')
);

React: 关于States.md

相似于Android的生命周期调节参数,此外state必须在定义它的那个class里面使用。

另外能够将state传到子元素,不过不能传给其余同级元素或者父元素

所以只可能出现Down Flow不可能向上传递。

另外stateful的Component和stateless的Component彻底能够随意交叉使用,反正数据均可以相互传递

<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
<FormattedDate date={this.state.date} />

生命周期

对于一个Component:

  • 初始化的时候的操做叫作Mounting
  • 销毁的操做叫作unMounting

而后能够在这两个事件进行监听

  • componentDidMount()事件会在Component渲染成功时执行
  • componentWillUnmount()事件会在Component销毁的时候执行

所以对于一个定时器来讲,应该在componentDidMount()事件里面注册Timer而且在componentWillUnmount()事件里面关闭Timer

而后在Timer里面必须更新state数据,由于咱们会将state数据输出出来,更新state须要执行setState(),将参数传进去就行

简单易懂

Timer的示例

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 (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

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

Using State Correctly

几个关于setState()的要点:

1. Do Not Modify State Directly

// Wrong
this.state.comment = 'Hello';

// Correct
this.setState({comment: 'Hello'});

The only place where you can assign this.state is the constructor.

2. State Updates May Be Asynchronous

所以不能直接使用state来overwite state

React may batch multiple setState() calls into a single update for performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

For example, this code may fail to update the counter:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:

写一个闭包能够解决问题

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

3. State Updates are Merged

When you call setState(), React merges the object you provide into the current state.

使用 setState()的时候,只要没有提供value的state都不会改变

For example, your state may contain several independent variables:

  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

Then you can update them independently with separate setState()calls:

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

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

The merging is shallow, so this.setState({comments}) leaves this.state.posts intact, but completely replaces this.state.comments.

Converting a Function to a Class

  • You can convert a functional component like Clock to a class in five steps:
  • Create an ES6 class with the same name that extends React.Component.
  • Add a single empty method to it called render().
  • Move the body of the function into the render() method.
  • Replace props with this.props in the render() body.
  • Delete the remaining empty function declaration.
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

Adding Local State to a Class

We will move the date from props to state in three steps:

  1. Replace this.props.date with this.state.date in the render() method:
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

  1. Add a class constructor that assigns the initial this.state:
class Clock extends React.Component {
  constructor(props) {  //!!!!!!!!!!!!!!
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

Note how we pass props to the base constructor:

  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

Class components should always call the base constructor with props.

  1. Remove the date prop from the <Clock /> element:
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

We will later add the timer code back to the component itself.

The result looks like this:

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

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

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

来源: https://reactjs.org/docs/state-and-lifecycle.html

React: 关于Local States.md

React: JSX里面循环生成多个子元素.md

用这个方法能够循环生成多个子元素

function Welcome(props) {
    props.name = 'test';
  return <h1>Hello, {props.name}</h1>;
}

function WelcomeList(nameList) {
    var nameDOM = [];
    for (var i = 0; i < nameList.length; i++) {
        nameDOM.push(Welcome({name: nameList[i]}))
    }
    return nameDOM;
}

function Root() {
    var nameList = ["Mike","Jack","Dick"];
  return (
    <div>
        {WelcomeList(nameList)}
    </div>
  );
}

ReactDOM.render(
  <Root />,
  document.getElementById('root')
);
相关文章
相关标签/搜索