[WIP]React 核心概念

创建: 2019/05/01

 

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

 

   
   
   
JSX简介
 插值

 大括号 {} 

 ● 内部可放任何JavaScript表达式

const jsxElement = <p sampleProp={0}>{buildName(people)}</p>;

 

 jsx也是表达式

 被编译成函数

 ● 可以赋值给变量 

const buildName = (people) => {
  return `${people.sex}的${people.name}`
};
const people = {
  name: '妖怪',
  sex: '不男不女',
}
const jsxElement = <p sampleProp={0}>{buildName(people)}</p>;

 

 指定属性

 和html一样, 但要用驼峰写法(因为JSX是JS)

 ● 赋值可以双引号可以用插值(不要组合起来用)

// 双引号
<p sampleA="0"/>
// 插值
<p sampleB={1}/>

 

 嵌套

 ● JSX内部可以嵌套JSX

<p>测试
    <a src={link.url}>{link.text}</a>
</p>

 ● 对于空标签, 可以 /> 结尾

const blankElement = <p/>;

 

 自动转义

 JSX的所有内容自动转义

 ● 可以直接插入用户输入内容, 不用担心安全问题

 

 JSX 表示对象

 Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用

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

// 实际生成
const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
};

 

   
元素渲染
 根节点

 该节点内的所有内容都将由 React DOM 管理

 ● 可以有任意多个根节点

 渲染

 

ReactDOM.render(reactDOM, dom)

 

 将一个 React 元素渲染到根 DOM 节点中

 ● 参数

 

 reactDom  想要渲染的dom
 dom  渲染的位置

 

 更新已渲染的元素 

 重新调用ReactDOM.render

 ● React自动对比新旧ReactDOM, 只更新变化的部分

 

   
组件&Props
 定义组件

 组件名称必须以大写字母开头 

 ● 函数组件

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

 

 ● class组件

 渲染组件  接收到的参数会作为props传入
 组合组件  组件可以互相嵌套
 Props 的只读性

 所有 React 组件都必须像纯函数一样保护它们的 props 不被更改

 ● 需要实时变化的属性放入state

state&生命周期
 生命周期函数

 

 componentDidMount  DOM已渲染
 componentWillUnmount  DOM即将被清除

 

 state 

 React通过this.state来检测自身是否被改变

 ● 更新用setState(), 不要直接修改State

this.setState({a:1})

 如果要用到之前的props或states, 不可以直接在setState里面调用. 用函数

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

 

 ● 只有构造函数可以给state赋值

class Sample extends React.Component {
    constructor(props) {
        super(props);
        this.state = {...} // 构造函数处可以给state赋值
    }
}

 ● setState()是浅合并

 参数里没提到的保持原样

 

   
   
事件处理
 js关于事件处理相关

 传送门

 

 React 事件的命名采用小驼峰式

 例:  onClick 

 阻止默认事件

 不能用return false

 必须用 preventDefault 

 添加事件 

 一般不需要 addEventListener , 只需在渲染时添加监听器

 ● 监听函数设置成箭头函数, 以确保this正确 

class Events extends React.Component {
  constructor(props) {
    super(props);
  }
  clickHandle = e => {
    console.log(e);
  };
  render() {
    return (
      <div>
        <h1>title: events</h1>
        <p onClick={this.clickHandle}>click</p>
      </div>
    );
  }
}

 ● 若不设置为箭头函数, 为确保this正确

 构造器里使用bind

 

constructor(props) {
    super(props);
    this.clickHandle = this.clickHandle.bind(this);
}

 

 

 

 在调用时使用箭头函数(不建议)

 每次渲染都会生成创建不同的回调函数, 可能引起其他元素重新渲染

<button onClick={(e) => this.clickHandle(e)}>

 

 

 

 向事件函数传递参数

 React的事件对象 e 会被作为第二个参数传递

 箭头函数  
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

 如果通过箭头函数的方式,事件对象必须显式的进行传递 

 Function.prototype.bind

 通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递

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

 

 

 

条件渲染
 阻止渲染  render内部返回null
 与运算符&&  
a && b

 若a可转换为true,则返回b;否则,返回a

 三项运算符  
con ? a : b

 

   
列表&key
 构建列表组件

 

class ListKey extends React.Component {
  constructor(props) {
    super(props);
    this.datas = new Array(10).fill(Math.random()*100).map((v, i) => {return v+i});
    this.listItems = this.datas.map((v, i) => {
      return (
        <li key={i}>data: {parseInt(v)}</li>
      );
    });
  }
  render() {
    return (
      <div>
        <h1>title: list & key</h1>
        <ul>{this.listItems}</ul>
      </div>
    );
  }
}

 

 

 key

 key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。

 ● 尽量在 map() 方法中的元素需要设置 key 属性

this.datas = new Array(10).fill(Math.random()*100).map((v, i) => {return v+i});
this.listItems = this.datas.map((v, i) => {
  return (
    <li key={i}>data: {parseInt(v)}</li>
  );
});

 

 ● 数组元素中使用的 key 在其兄弟节点之间应该是独一无二的

 ● key 会传递信息给 React ,但不会传递给你的组件

 需要key值的用其他属性名显示传递

<li key={i} mykey={i}>data: {parseInt(v)}</li>

 

   
   
表单
 受控组件

 所有事件都需要添加处理函数

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          参与:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          来宾人数:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

 

 

   
   
   
状态提升
   将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的“状态提升”
   
   
   
组合&继承
 包含关系

 ● 嵌套的组件全部在 props.children 里

 ● 预留placeholder可以用任何名字, 可以传入任何对象

function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">
        {props.left}
      </div>
      <div className="SplitPane-right">
        {props.right}
      </div>
    </div>
  );
}

function App() {
  return (
    <SplitPane
      left={
        <Contacts />
      }
      right={
        <Chat />
      } />
  );
}

 

 

 特例关系

 “特殊”组件可以通过 props 定制并渲染“一般”组件

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-message">
        {props.message}
      </p>
    </FancyBorder>
  );
}

function WelcomeDialog() {
  return (
    <Dialog
      title="Welcome"
      message="Thank you for visiting our spacecraft!" />

  );
}

 

 

 继承  不需要使用
   
React哲学
 用 React 创建一个静态版本

 渲染 UI 和添加交互分开

 确定 UI state 的最小(且完整)表示  

 通过问自己以下三个问题,你可以逐个检查相应数据是否属于 state:

  1. 该数据是否是由父组件通过 props 传递而来的?如果是,那它应该不是 state。
  2. 该数据是否随时间的推移而保持不变?如果是,那它应该也不是 state。
  3. 你能否根据其他 state 或 props 计算出该数据的值?如果是,那它也不是 state。
 确定 state 放置的位置  

 对于应用中的每一个 state:

  • 找到根据这个 state 进行渲染的所有组件。
  • 找到他们的共同所有者(common owner)组件(在组件层级上高于所有需要该 state 的组件)。
  • 该共同所有者组件或者比它层级更高的组件应该拥有该 state。
  • 如果你找不到一个合适的位置来存放该 state,就可以直接创建一个新的组件来存放该 state,并将这一新组件置于高于共同所有者组件层级的位置。
 添加反向数据流  回调
posted @ 2019-05-01 11:48  懒虫哥哥  阅读(125)  评论(0编辑  收藏  举报