A Bite Of React(2) Component, Props and State

  • component

    • component:用户自己定义的元素
const element = <Welcome name="Sara" />;
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

遇到自己定义的component Welcom,React会将它的属性(name)作为对象传递给组建Welcom,即{name=‘Sara‘}

eg:components名称必须以大写字母开头,<div /> 表示一个DOM标签,但 <Welcome /> 表示一个组件,并且在使用该组件时你必须定义或引入它。

    • 组合component:component可以在输出中引用其他的组建。一个新的React应用程序的顶部是一个App组件。但是,如果要将React集成到现有应用程序中,则可以从下而上使用像Button这样的小组件作为开始,并逐渐运用到视图层的顶部。

eg:

警告:

组件的返回值只能有一个根元素。这也是我们要用一个<div>来包裹所有<Welcome />元素的原因。

    • 提取component
  • Props

    • props:props其实就是自定义组件的属性,会打包作为一个object传递给component
    • props的只读性:无论是functional based component 还是 class based component都不能修改自己的props
  • State

    • 如何定义state:

      React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

    1. State必须能代表一个组件UI呈现的完整状态集,即组件的任何UI改变,都可以从State的变化中反映出来;同时,State还必须是代表一个组件UI呈现的最小状态集,即State中的所有状态都是用于反映组件UI的变化,没有任何多余的状态,也不需要通过其他状态计算而来的中间状态。
    2. 组件中用到的一个变量是不是应该作为组件State,可以通过下面的4条依据进行判断:
      1. 这个变量是否是通过Props从父组件中获取?如果是,那么它不是一个状态。
      2. 这个变量是否在组件的整个生命周期中都保持不变?如果是,那么它不是一个状态。
      3. 这个变量是否可以通过其他状态(State)或者属性(Props)计算得到?如果是,那么它不是一个状态。
      4. 这个变量是否在组件的render方法中使用?如果不是,那么它不是一个状态。这种情况下,这个变量更适合定义为组件的一个普通属性,例如组件中用到的定时器,就应该直接定义为this.timer,而不是this.state.timer。
    • State和prop的区别:

除了State, 组件的Props也是和组件的UI有关的。他们之间的主要区别是:State是可变的,是组件内部维护的一组用于反映组件UI变化的状态集合;而Props对于使用它的组件来说,是只读的,要想修改Props,只能通过该组件的父组件修改。在组件状态上移的场景中,父组件正是通过子组件的Props, 传递给子组件其所需要的状态。

    • 如何证正确的修改State

      • 不能直接修改state:在constructor之中用this.state来初始化state(是一个object)。在其余的地方用this.setState()来更新。
      • State的更新是异步的:调用setState,组件的state并不会立即改变,setState只是把要修改的状态放入一个队列中,React会优化真正的执行时机,并且React会出于性能原因,可能会将多次setState的状态修改合并成一次状态修改。所以不要依赖当前的State,计算下个State。当真正执行状态修改时,依赖的this.state并不能保证是最新的State,因为React会把多次State的修改合并成一次,这时,this.state将还是这几次State修改前的State。另外需要注意的事,同样不能依赖当前的Props计算下个状态,因为Props一般也是从父组件的State中获取,依然无法确定在组件状态更新时的值。

举个例子,对于一个电商类应用,在我们的购物车中,当我们点击一次购买数量按钮,购买的数量就会加1,如果我们连续点击了两次按钮,就会连续调用两次this.setState({quantity: this.state.quantity + 1}),在React合并多次修改为一次的情况下,相当于等价执行了如下代码:



Object.assign(
  previousState,
  {quantity: this.state.quantity + 1},
  {quantity: this.state.quantity + 1}
) 

于是乎,后面的操作覆盖掉了前面的操作,最终购买的数量只增加了1个。

如果你真的有这样的需求,可以使用另一个接收一个函数作为参数的setState,这个函数有两个参数,第一个是当前最新状态(本次组件状态修改后的状态)的前一个状态preState(本次组件状态修改前的状态),第二个参数是当前最新的属性props。如下所示:

// 正确
this.setState((preState, props) => {
  counter: preState.quantity + 1;
})
      •  State 的更新是一个浅合并(Shallow Merge)的过程

当调用setState修改组件状态时,只需要传入发生改变的State,而不是组件完整的State,因为组件State的更新是一个浅合并(Shallow Merge)的过程。例如,一个组件的状态为:

this.state = {
  title : ‘React‘,
  content : ‘React is an wonderful JS library!‘
}

      当只需要修改状态title时,只需要将修改后的title传给setState

this.setState({title: ‘Reactjs‘});

React会合并新的title到原来的组件状态中,同时保留原有的状态content,合并后的State为:

{
  title : ‘Reactjs‘,
  content : ‘React is an wonderful JS library!‘
}
    • 如何证正确的修改State

React官方建议把State当作是不可变对象,一方面是如果直接修改this.state,组件并不会重新render;另一方面State中包含的所有状态都应该是不可变对象。当State中的某个状态发生变化,我们应该重新创建这个状态对象,而不是直接修改原来的状态。那么,当状态发生变化时,如何创建新的状态呢?根据状态的类型,可以分成三种情况:

      • 状态的类型是不可变类型(数字,字符串,布尔值,null, undefined)

这种情况最简单,因为状态是不可变类型,直接给要修改的状态赋一个新值即可。如要修改count(数字类型)、title(字符串类型)、success(布尔类型)三个状态:

this.setState({
  count: 1,
  title: ‘Redux‘,
  success: true
}) 
      • 状态的类型是数组

如有一个数组类型的状态books,当向books中增加一本书时,使用数组的concat方法或ES6的数组扩展语法(spread syntax):

// 方法一:将state先赋值给另外的变量,然后使用concat创建新数组
var books = this.state.books;
this.setState({
  books: books.concat([‘React Guide‘]);
})

// 方法二:使用preState、concat创建新数组
this.setState(preState => ({
  books: preState.books.concat([‘React Guide‘]);
}))

// 方法三:ES6 spread syntax
this.setState(preState => ({
  books: [...preState.books, ‘React Guide‘];
}))

      当从books中截取部分元素作为新状态时,使用数组的slice方法:

// 方法一:将state先赋值给另外的变量,然后使用slice创建新数组
var books = this.state.books;
this.setState({
  books: books.slice(1,3);
})

// 方法二:使用preState、slice创建新数组
this.setState(preState => ({
  books: preState.books.slice(1,3);
}))

      当从books中过滤部分元素后,作为新状态时,使用数组的filter方法:

// 方法一:将state先赋值给另外的变量,然后使用filter创建新数组
var books = this.state.books;
this.setState({
  books: books.filter(item => {
    return item != ‘React‘;
  });
})

// 方法二:使用preState、filter创建新数组
this.setState(preState => ({
  books: preState.books.filter(item => {
    return item != ‘React‘;
  });
}))

注意不要使用push、pop、shift、unshift、splice等方法修改数组类型的状态,因为这些方法都是在原数组的基础上修改,而concat、slice、filter会返回一个新的数组。

      • 状态的类型是普通对象(不包括字符串,数组)

        ES6的Object.assign方法

// 方法一:将state先赋值给另外的变量,然后使用Object.assign创建新对象
var owner = this.setState.owner;
this.setState({
  owner: Object.assign({}, owner, {name: ‘Jason‘});
})

// 方法二:使用preState、Object.assign创建新对象
this.setState(preState => ({
  owner: Object.assign({}, preState.owner, {name: ‘Jason‘});
}))

        使用对象扩展语法

// 方法一:将state先赋值给另外的变量,然后使用对象扩展语法创建新对象
var owner = this.setState.owner;
this.setState({
  owner: {...owner, {name: ‘Jason‘}};
})

// 方法二:使用preState、对象扩展语法创建新对象
this.setState(preState => ({
  owner: {...preState.owner, {name: ‘Jason‘}};
}))

来源:https://juejin.im/entry/59522bdb6fb9a06b9a516113

   https://doc.react-china.org/docs/state-and-lifecycle.html        

时间: 2024-10-07 17:40:55

A Bite Of React(2) Component, Props and State的相关文章

React Native的props和state的介绍

this.props 可以通过将属性传递给构造函数constructor来实例化组件,这些属性就叫做props.在组件渲染的时候,可以通过this.props访问该组件的属性.但是不在组件方法里面修改props. 该组件的父元素一般会修改它孩子的属性,然后孩子重新渲染将这些属性展现出来.当然,孩子不一定重新渲染,具体看shouldComponentUpdate()方法的返回值,该方法的默认值是返回值true,也就是默认会重新渲染.孩子可以重写该方法返回false,就不会重新渲染,一般这样做是为了

React Native 快速入门之认识Props和State

眼下React Native(以后简称RN)越来越火,我也要投入到学习当中.对于一个前端来说,还是有些难度.因为本人觉得这是一个App开发的领域,自然是不同.编写本文的时候,RN的版本为0.21.0.我们马上以代码进入今天的学习. 'use strict'; import React, { AppRegistry, Component, StyleSheet, Text, View } from 'react-native'; class Hello extends Component { re

React入门---属性(props)-8

Props 和 State对于组件Component是非常重要的两个属性. 区别:State对于模块来说是 自身属性:   Props对于模块来说是 外来属性: 同样的,props也是只作用于当前的组件,绝不影响其他组件: 给组件 <ComponentFooter> 添加props属性和属性值: 例:从父组件index.js给子组件footer.js传送数据: class Index extends React.Component{ render(){ return( //里面分别是 头部 主

Webpack + React 开发 03 props

React中组件的用法与原生的 HTML 标签完全一致,可以任意加入属性,比如 <HelloWorld name="John"> ,就是 HelloWorld 组件加入一个 name 属性,值为 John.和直接使用 <div name="John"> 不同,React组件被渲染出来之后,在渲染之后的dom节点中是不能直接看得到 name 属性的,怎么获取呢?组件的属性可以在组件类的 this.props 对象上获取,比如 name 属性就可

React中Props 和 State用法

React中Props 和 State用法 1.本质 一句话概括,props 是组件对外的接口,state 是组件对内的接口.组件内可以引用其他组件,组件之间的引用形成了一个树状结构(组件树),如果下层组件需要使用上层组件的数据或方法,上层组件就可以通过下层组件的props属性进行传递,因此props是组件对外的接口.组件除了使用上层组件传递的数据外,自身也可能需要维护管理数据,这就是组件对内的接口state.根据对外接口props 和对内接口state,组件计算出对应界面的UI=>UI = C

react事件绑定的三种常见方式以及解决Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state问题思路

在 React 组件中,每个方法的上下文都会指向该组件的实例,即自动绑定 this 为当前组件. 而且 React 还会对这种引用进行缓存,以达到 CPU 和内存的优化.在使用 ES6 classes 或者纯 函数时,这种自动绑定就不复存在了,我们需要手动实现 this 的绑定. 1.bind方法进行绑定,这个方法可以帮助我们绑定事件处理器内的 this ,并可以向事件处理器中传 递参数,如下图清晰明了: bind方法绑定 2.箭头函数进行绑定,箭头函数不仅是函数的“语法糖”,它还自动绑定了定义

React + TypeScript 默认 Props 的处理

React 中的默认 Props 通过组件的 defaultProps 属性可为其 Props 指定默认值. 以下示例来自 React 官方文档 - Default Prop Values: class Greeting extends React.Component { render() { return ( <h1>Hello, {this.props.name}</h1> ); } } // Specifies the default values for props: Gr

React中constructor(props){}究竟是什么,以及super(props)与super()

定义class组件,为什么需要加上 super() ? 我们尝试去掉 super() 看看编译的结果: constructor() { this.state = {searchStr: ''}; this.handleChange = this.handleChange.bind(this); } 编译错误: 提示没有在this之前加上super() 其实就是少了super(),导致了this的 Reference Error class MyComponent extends React.Co

关于props和state(React)

React的数据模型分为共有数据和私有数据,共有数据可以在组件间进行传递,私有数据为当前组件私有.共有数据在React中使用props对象来调用,它包含标签所有的属性名称和属性值,props对象有三个特性,单向流动性.显示传递性和只读性.单向流动性是指React的数据只能由父组件传递到子组件,而不能由子组件传递到父组件:显示传递性是指必须明确地在子组件中通过属性赋值,数据才可以传递到子组件:只读性是指props数据是只读的,数据修改后并未改变原始的数据模型,而是会新生成一份数据模型,并将新的数据