React 学习笔记(二)

Learn from React 官方文档

一、Rendering Elements

1. Rendering an Element into the DOM


2. Updating the Rendered Element

React elements 是不可改变的,一旦创建,就不可以改变它的子节点或者属性。


上例每秒调用一次 tick() 函数,每次调用重新调用一次 ReactDOM.render() ,更新 React element 的内容。

React 只更新有必要更新的内容。 React DOM 把新的element和比较之前的element 比较,将不同的地方加以更新。例如打开浏览器控制台可以看到,在上例中只改变了 h2 的文本。

二、Components and Props

  • 组件将 UI 分成独立的、可重用的小块。
  • 组件和 JavaScript 函数相似。它们接受任意输入 (called "props"),返回描述所要显示的 React elements
  • 组件的返回必须是一个单独的 element 而不可以是多个,所以可以用一个
    将其他元素包裹起来
  • 尽可能将一个组件分成多个更小的组件。

1. Functional and Class Components

  • way 1: Functional Components
function Welcome (props) {
        return 

Hello, {props.name}

; }

接收参数:props 一个对象
返回:一个 React element

  • way 2: Class Components
class Welcome extends React.Component {
    render() {
        return 

Hello, {this.props.name}

; } }

2. Rendering a Component


  • 当 React 遇到用户自定义的组件时,它给组件传递一个包含 JSX 属性的对象,这个对象是 props
{
    name:"Sara"
}  //props 对象
  • 上例的执行:

  • 调用 ReactDOM.render() ,插入一个 组件

  • React 调用 Welcome 组件,props 对象为 {name:"Sara"}

  • Welcome组件输出

    Hello Sara

  • React 更新 DOM 节点

  • 组件的名字一定要大写字母开头

3. Composing Components

组件内使用可以用另一个组件:


4. Props are Read-Only

React 必须遵守的一条严格的准则:
所有的 React 组件必须是 pure function,因为 props 是只读的

pure function: 函数体的执行不修改传入的参数值

三、State and Lifecycle

  • state 可以动态地改变数据。它是私有的和完全由组件控制的。
  • 使用 Class Component 定义的组件比 Functional Component 多了一些特性,就是拥有 例如:state 。
  • 生命周期钩子 (lifecycle hooks):声明在组件中,当组件 mountunmount(刚植入和刚移除)时执行的方法.
  • The componentDidMount() hook runs after the component output has been rendered to the DOM.(componentDidMount() 方法在组件的输出植入到 DOM 中的时候执行)。
  • this.propsthis.state 这些是在 React.Component 中定义的,用户自定义的组件继承了 React.Component,所以不需要重新声明。
  • 在拥有许多组件的应用中,当组件被移除时,释放组件已经占用的资源是非常重要的。

1. 时钟例子

//时钟例子:

  • 上面的时钟代码的执行过程:
  • 组件传递给 ReactDOM.render(), React 调用 Clock 组件的 constructor,由于 Clock 组件需要先显示当前的时间,在 constructor 中初始化 this.state 的值。
  • React 接着调用 Clock 组件的 render() 方法,Clock 组件 render() 的输出返回要渲染的 DOM 元素。
  • 当 DOM 元素插入后,React 调用生命周期钩子 componentDidMount()。在这个方法中,Clock 组件生成一个计时器,要求浏览器每秒钟调用一次 tick() 函数。
  • tick() 方法中调用 this.setState() 方法,更新 state 的值,更新 DOM 的内容。
  • Clock 组件从 DOM 中移除时,React调用 componentWillUnmout() 方法,清除计时器。

2. 正确使用 state

  • 不要使用赋值的方法直接修改 state 的值:
this.state.comment = 'hello'; //wrong

要使用 setState()方法更新state的值

this.setState({ comment:'hello'}); //correct

只有在constructor中可以直接为this.state分配值

constructor(props) {
  super(props);
  this.state = {comment:'hello'};
}
  • state 是异步更新的
    由于 this.propsthis.state 是异步更新的,所以不应该直接使用它们来设置新的 state
this.setState({
  counter: this.state.counter + this.props.increment,
}); //wrong

使用接收一个函数作为参数的 setState()
第一个参数:prevState(state 的上一个值)
第二个参数:props

this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));  //correct
  • this.state 的值可以是一个对象,这个对象包含几个独立的属性,可以用多个 setState() 独立的更新每一个属性

  • 单向数据流
    一个组件可以将它的 state 值作为 props 传递给它的子组件而与外部的其他组件无关。

四、Handling Events


五、Conditional Rendering

1. example 1:

有两个组件:一个是 LoginGreeting 另一个是 LogoutGreeting
在第三个组件 Greeting 中,使用了这两个组件中的其中一个,根据 Greeting 组件的 props 对象的 greet 属性值


2. example 2: 使用元素变量

根据不同的 state 值,将不同的组件赋给一个元素变量,在另一个组件中使用变量名插入这个组件。


3. example 3: 用短路与 && 操作符

只要当 && 的左操作数为假时,表达式返回假,不计算右操作数;只有当左操作数为真时,才会计算右操作数的值,返回右操作数的值。


4. example 4: condition? true : false

condition 的值为真时,返回冒号左边的表达式的值,当 condition 的值为假时,返回冒号右边的表达式的值


也可以返回更大的表达式,但是降低了可读性:

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    
{isLoggedIn ? ( //isLoggedIn 为 true 时返回 LogoutButton 组件 ) : ( //isLoggedIn 为 false 时返回 LoginButton 组件 )}
); }

5. example 5: 使用返回null来隐藏一个组件


  • 组件返回 null 不影响组件的生命周期方法,例如 componentWillUpdatecomponentDidUpdate 依然可以被调用。

六、Lists and Keys

1. example 1:

使用 map() 函数遍历 numbers 数组,每次遍历返回一个

  • 元素,将遍历后返回的结果数组赋给 listItems,用一个
      将结果数组包裹起来植入 DOM

      
      

      2. example 2:

      组件接收一个数组,返回一个列表:

      
      

      3. example 3:

      当运行上面那些代码的时候,会在控制台得到一个 warning,需要给列表元素增加 key 属性

      
      

      4. example 4:

      可以为数组元素对象设置一个ID属性 ,用来作为 key

      
      

      如果没有ID属性作为 key ,也可以使用数组元素的索引作为 key:
      (不推荐使用索引 index 作为 key,因为当数组可以重排的时候,速度会变慢)

      
      

      5. example 5:

      拆分组件的时候,要将 key 作为组件的属性,而不要把它放在组件返回的

    • 元素中

      //wrong, 这样子相当于没有设置 key,控制台仍然会有关于 key 的 warning
      
      
      //correct
      
      

      6. example 6:

      一个数组中每个数组元素的 key 必须互不相同,但是不同数组可以有相同的 key

      
      

      七、 Forms

      1. example 1: Controlled Component

      value 值由 React 的 state 控制:

      
      

      2. example 2: textarea

      
      

      3. example 3: select

      在 React 中通过给 value 值与 value 值相同,则选中该
      这种方法更为方便,只要更新 的时候,可以通过给每个 设置 name 属性,让事件处理函数根据 event.target.name 的值来决定做什么事情

      
      

      [ name ]: ES6 计算属性名

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

      在 ES5 中相当于:

      var partialState = {};
      partialState[name] = value;
      this.setState(partialState);
      

      八、Lifting State Up

      • 经常在几个组件中,他们的数据受同一个变化的数据的影响,这时就要把 state 提到离这些组件最近的共同的父组件中。

      • 例如下面的例子中,输入摄氏度的组件 和输入华氏度的组件 他们的 value 值相互影响,在摄氏度输入框输入的摄氏度值会转化为华氏度显示在华氏度的输入框,同样,输入的华氏度也会转化为摄氏度在摄氏度输入框显示。

      • 他们有共同的父组件 ,将 state 值设置在 中,根据 state 值的scale 属性值判断是哪个输入框在输入,由此可将另一个输入框根据华氏度和摄氏度的转换公式进行转换。

      • 组件根据摄氏度输入框的值显示不同的提示语,摄氏度值大于等于100,则显示:The water would boil. 摄氏度值小于100,则显示:The water would not boil.

      
      
      React 学习笔记(二)_第1张图片
      Temperature
      React 学习笔记(二)_第2张图片
      Temperature

      九、Composition

      1. example 1:

      有一些组件一开始我们不知道他们的子节点是什么的时候,可以使用 {props.children} 在使用这个组件的时候再将子节点作为 props 的一个属性传递给该组件。

      function Dialog(props) {
          return(
              
      {props.children}
      ); } function WelcomeDialog() { return( // Dialog 标签中间的 内容就作为Dialog组件的子节点

      Welcome!

      Thankyou for your visit!

      ); }

      2. example 2:

      也可以使用自定义的属性名,在组件中多处插入不同的内容:

      function SplitPane(props) {
          return(
              
      {props.left}
      {props.right}
      ); } function App() { return( // 是两个已经定义的组件 } right={} /> ); }

      3. example 3:Specialization

      专门化:定义一个组件,在另一个组件中通过传入属性值,将该组件具体化为一个特殊的组件。

      // 无内容的对话框组件轮廓
      function Dialog(props) {
          return(
              

      {props.title}

      {props.message}

      ); } //设置组件的属性值,传入具体的内容,使之成为一个专门的有特殊用处的 组件 function WelcomeDialog() { return( ); }

      十、Thinking in React

      • React 的目的是使用 JavaScript 快速地构建大型的 Web Apps。
      • 使用 React 构建项目的流程如下例:
        首先由你的 app 样式图开始,将你的 app 划分为由各个组件组成的一个大组件:
      React 学习笔记(二)_第3张图片
      app样式图
      // 你的数据
      [
        {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
        {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
        {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
        {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
        {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
        {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
      ];
      

      Step 1: Break The UI Into A Component Hierarchy

      • 把 UI 按层次划分成一个个组件:首先用一个个方框将你的 UI 划分成一个个组件,并给每个组件命名,根据一个组件只完成一件事的原则来划分组件。
      React 学习笔记(二)_第4张图片
      Paste_Image.png
      • 明确每个组件的功能:
        FilterableProductTable (orange) 包含了整个样例
        SearchBar (blue) 接收所有用户输入,包括输入框的输入和复选框的勾选
        ProductTable (green) 基于用户的输入显示和过滤数据集
        ProductCategoryRow (turquoise) 显示每个分类的标题
        ProductRow (red) 显示每一种产品的信息

      这样就将整个样例如下划分了层次,包含在一个组件下的将作为它的子元素:

      React 学习笔记(二)_第5张图片
      Paste_Image.png

      Step 2: Build A Static Version in React

      • 用React建立静态的样式:这个过程使用 props 从父组件传递数据给子组件,而不要使用 statestate 是用来交互的,传递动态变化的数据的。
      • 可以采用自顶向下也可以采用自底向上的顺序构建每一个组件。

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

      • 思考本例子中的每一个数据有:

      • 原始的产品表单

      • 用户的输入文本

      • 复选框的值

      • 过滤的产品表单

      • 决定哪一项数据成为 state 思考的三个问题:

      • 它是通过父组件的 props 属性传递来的吗?如果是,它不是 state

      • 它是否在一段时间内保持不变?如果是,它不是 state

      • 你是否可以通过其他 state 或者 props 值计算出它的值?如果可以,它不是 state

      • 在本例中,原始的产品表单是通过 props 传递的,不是 state
        用户输入的文本和复选框的值是动态的随着用户任意变化的,它是 state
        过滤的产品表单可以通过用户的输入和复选框的值计算显示,不是 state
        因此,本例的 state 是用户输入的文本和复选框的值

      Step 4: Identify Where Your State Should Live

      • 明确state值放置的位置:
        React 是单向数据流的;
        每一个组件都根据 state 植入某些内容;
        每个组件有一个共同的父组件,这个组件拥有 state

      • 本例中,过滤的产品表单 ProductTable 是根据 state 值计算出来的,SearchBar 的文本框值和复选框值根据 state 来显示,每个组件共同的父组件是 FilterableProductTable,因此 FilterableProductTable 拥有 state:输入的过滤文本和复选框的值。

      Step 5: Add Inverse Data Flow

      最后本例的代码及最后的样式见我的Github。

      React 学习笔记(二)_第6张图片
      最后的样式

      十一、Typechecking With PropTypes

      1. React.PropTypes

      为属性设置类型:

      
      
      • 在上面的例子中,只有当 name 属性的类型为 string 时,才能正常显示;
      • name=123 时,不符合设置的name属性类型,所以控制台报错;

      2. Requiring Single Child

      使用 React.PropTypes.element 可以要求传递给组件的子元素只能有一个:

      
      

      如果传入多个子元素:

      
      

      控制台提示warning:

      Paste_Image.png

      3. Default Prop Values

      通过在 defaultProps 属性中设置默认的属性值,用于确保 this.props.name 有值,如果父组件没有设置属性值的话。同样地, propTypes 也会检测 defaultProps 中属性的类型。

      
      

      十二、Refs and the DOM

      1. Adding a Ref to a DOM Element

      • ref 属性带有一个回调函数,这个回调函数在组件 mounted 或者 unmounted 的时候执行;
      • ref 用在 html 元素时,ref 的回调函数接收拥有这个 ref 的 DOM 元素作为它的参数;
      
      
      • 可以把 ref 添加到用 class 定义的组件上
      • 不可以把 ref 添加到用 function 定义的组件上
      • 可以在一个用 function 定义的组件内为一个用 class 定义的组件添加 ref
  • 你可能感兴趣的:(React 学习笔记(二))