The Road to learn React书籍学习笔记(第二章)

react

组件的内部状态

组件的内部状态也称为局部状态,允许保存、修改和删除在组件内部的属性,使用ES6类组件可以在构造函数中初始化组件的状态。构造函数只会在组件初始化的时候调用一次

类构造函数

1 class App extends Component{

2 constructor(props){

3 super(props);

4 }

5 }

使用ES6编写的组件有一个构造函数时,需要强制地使用 super() 方法, 因为这个 App组件Component 的子类,因为需要在 App组件 声明 extends Component 也可以调用 super(props),它会在构造函数中设置 this.props 以供构造函数中访问。否则在构造函数中访问 this.props ,会得到 undefined

例子,组件的初始状态是一个列表

 1 const list = [

2 {

3 title:'React',

4 url: 'https://facebook.github.io/react/',

5 author: 'Jordan Walke',

6 num_comments: 3,

7 points: 4,

8 objectID: 0,

9 }

10 ];

11 ​

12 class App extends Component{

13 constructor(props){

14 super(props);

15 this.state = {

16 list : list,

17 }

18 }

19 }

state 通过使用 this 绑定在类上,因此可以在整个组件中访问到 state。通过 render() 方法可以映射一个在组件外定义静态列表

 1 class App extends Component{

2 render(){

3 return(

4 <div className = "App">

5 {this.state.list.map(item =>

6 <div key = {item.objectID}>

7 <span><a href = {item.url}>{item.title}</a></span>

8 <span>{item.author}</span>

9 <span>{item.num_comments}</span>

10 <span>{item.points}</span>

11 </div>

12 )

13 }

14 </div>

15 );

16 }

17 }

现在list是㢟的一部分,它在组件的 state 中,可以从list添加、修改、删除列表项。组件的 render 会再次运行,可以简单修改组件内部状态,确保组件重新渲染并且展示从内部状态获取到的正确数据 修改 state 可以使用 setState() 方法来修改

ES6 对象初始化

初始化例子

1 const name = 'Laibh';

2 const user = {

3 name : name

4 };

当对象中属性名与变量名相同时可以如下操作

1 const name = 'Laibh'; 

2 const user = {

3 name

4 };

在应用程序中,列表变量名与状态属性名称共享同一名称

1 //ES5 

2 this.state = {

3 list:list

4 }

5 ​

6 //ES6

7 this.state = {

8 list

9 };

简写方法名

 1 //ES5

2 var userService = {

3 getUserName :function(user){

4 return user.firstname + ' ' + user.lastname;

5 }

6 }

7 ​

8 //ES6

9 const userService = {

10 getUserName(user){

11 return user.firstname + ' ' + user.lastname;

12 }

13 }

计算属性名

 1 //ES5

2 var user = {

3 name:'Laibh'

4 }

5 ​

6 //ES6

7 const key = 'name';

8 const user = {

9 [key] :'Laibh'

10 }

单向数据流

组件中有一些内部的 state,练习 state 操作的好方式增加一些组件的互动 为列表增加一个删除按钮

 1   class App extends Component {

2 ​

3 render() {

4 return (

5 <div className="App">

6 {this.state.list.map(item =>

7 <div key={item.objectID}>

8 <span>

9 <a href={item.url}>{item.title}</a>

10 </span>

11 <span>{item.author}</span>

12 <span>{item.num_comments}</span>

13 <span>{item.points}</span>

14 <span>

15 <button

16 onClick={() => this.onDismiss(item.objectID)}

17 type="button"

18 >

19 Dismiss

20 </button>

21 </span>

22 </div>

23 )}

24 </div>

25 );

26 }

27 }

上面类中,onDismiss() 还没有被定义,它通过id来标识哪个应该被删除,此函数绑定到类,就成为了类方法,所以访问它的时候要用 this.onDismiss() 而不是用 onDismiss()this 对象是类的实例,为了将 onDismiss() 定义为类方法,需要在构造函数中绑定它。并定义它的逻辑功能

 1   class App extends Component {

2 ​

3 constructor(props) {

4 super(props);

5 ​

6 this.state = {

7 list,

8 };

9 ​

10 this.onDismiss = this.onDismiss.bind(this);

11 }

12 onDismiss(id) {

13 ...

14 }

15 ​

16 render() {

17 ...

18 }

19 }

可以使用JavaScript内置的 filter 方法来删除列表的一项,它会遍历整个列表,通过条件来过滤,匹配的返回 true 并留在列表中

1 onDismiss(id){

2 const updateList = this.state.list.filter(function isNotId(item){

3 return item.objectID !== id

4 });

5 }

或者一行箭头函数

1 onDismiss(id){

2 const updateList = this.state.list.filter(item => item.objectID !== id);

3 }

接着要更新数据

this.setState({list:updateList});

绑定

类不会自动绑定 this 到实例上 需要自己绑定

1 constructor() {

2 super();

3 ​

4 this.onClickMe = this.onClickMe.bind(this);

5 }

类的绑定方法也有人写在其他地方,例如render()函数中

1 render(){

2 return(

3 <button onClick = {this.onClickMe.bind(this)}>Click Me</button>

4 )

5 }

但是应该避免这样使用,因为它会在每次 render() 方法执行的时绑定类方法。组件每次更新都会导致性能消耗,当在构造函数中绑定的时候,绑定只会在组件实例化时运行一次,这样是一个更好的方式

另外有一些人剔除在构造函数中定义业务逻辑类方法

1 constructor(){

2 super();

3 this.onClick = () =>{

4 conlose.log(this);

5 }

6 }

这样随着时间推移会让构造函数变得混乱,避免使用。构造函数的目的只是实例化类以及所有的属性

事件处理

1 <button

2 onClick={() => this.onDismiss(item.objectID)}

3 type="button">

4 Dismiss

5 </button>

当传递一个参数到类的方法,需要将它封装到另一个(箭头)函数中,由于要传递给事件处理器使用,因为它必须是一个函数,而下面的这个代码不会工作。因为类方法会在浏览器中打开程序时候立即执行

1 <button onClick = {this.onDismiss(item.objectID)}>

2 Dismiss

3 </button>

倘若写成

1 <button onClick = {onDismiss}>

2 Dismiss

3 </button>

就不会立即执行,但是需要传参数,所以就不这么用

另外的一个解决方案是在外部定义一个包装函数,并且只将定义的函数传递给处理程序。因为需要访问特定的列表项,所以它必须位于 map 函数块的内部

 1 class App extends Component{

2 render(){

3 return(

4 <div className = "App">

5 {this.state.list.map(item =>

6 const onHandldDismiss = () =>

7 this.onDismiss(item.objectID);

8 ​

9 return(

10 <div key={item.objectID}>

11 <span>

12 <a href={item.url}>{item.title}</a>

13 </span>

14 <span>{item.author}</span>

15 <span>{item.num_comments}</span>

16 <span>{item.points}</span>

17 <span>

18 <button

19 onClick={onHandleDismiss}

20 type="button"

21 >

22 Dismiss

23 </button>

24 </span>

25 </div>

26 )

27 )}

28 </div>

29 )

30 }

31 }

在事件处理程序中使用箭头函数对性能会有影响

和表单互动

 1 const list = [{

2 title: 'React',

3 url: 'https://facebook.github.io/react',

4 author: 'Jordan Walke',

5 num_comments: 3,

6 points: 4,

7 objectID: 0,

8 }, {

9 title: 'Redux',

10 url: 'https://github.com/reactjs/redux',

11 author: 'Dan Abramov, Andrew Clark',

12 num_comments: 2,

13 points: 5,

14 objectID: 1,

15 }];

16 const isSearched = searchText => item => item.title.toLowerCase().includes(searchText.toLowerCase());

17 class FormP extends Component{

18 constructor(props){

19 super(props);

20 this.state = {list,searchText:''};

21 this.onSearchChange = this.onSearchChange.bind(this);

22 this.onDismiss = this.onDismiss.bind(this);

23 }

24 onSearchChange(e){

25 this.setState({searchText:e.target.value});

26 }

27 onDismiss(id){

28 console.log(this);

29 const updateList = this.state.list.filter(item =>

30 item.objectID !== id

31 );

32 this.setState({list:updateList});

33 }

34 render(){

35 return(

36 <div className = "FormP">

37 <form>

38 <input type="text" onChange = {this.onSearchChange}/>

39 </form>

40 {this.state.list.filter(isSearched(this.state.searchText)).map(

41 item =>

42 <div key = {item.objectID}>

43 <span>

44 <a href= {item.url}>{item.title}</a>

45 </span>

46 <span>{item.author}</span>

47 <span>{item.num_comments}</span>

48 <span>{item.points}</span>

49 <span>

50 <button onClick = {()=>this.onDismiss(item.objectID)}>Dismiss</button>

51 </span>

52 </div>

53 )}

54 </div>

55 )

56 }

57 }

58 ​

59 export default FormP;

ES6 解构

在JavaScript ES6 中有一个更方便的方法来访问对象和数组的属性,叫做解构。

 1   const user = {

2 firsname : 'L',

3 lastname : 'binhong'

4 }

5 ​

6 //ES5

7 var firstname = user.firstname;

8 var lastname = user.lastname;

9 ​

10 console.log(firstname + '' +lastname);

11 ​

12 //ES6

13 const {firstname, lastname} = user;

14 conlose.log(firstname + '' +lastname);

在JavaScript ES5中每次访问对象的属性都需要额外添加一行代码,但是ES6中就可以在一行中进行,可读性最好的方法就是将对象解构成多个属性时使用多行 对于数组也可以使用解构,可以保持代码的可读性

1 const user = ['1','2','3'];

2 const [

3 a,

4 b,

5 c

6 ] = user;

7 ​

8 console.log(a,b,c); //1,2,3

受控组件

表单元素 <input>/<select>/<textarea> 会以元素HTML的形式保存它们自己的状态,一旦有人从外部做了修改,就会修改内部的值,在React中这被称为不受控组件,因为它们自己处理状态,在React中,我们得把它们变成 受控元素

 1   class App extends Componet{

2 render(){

3 const {searchText,list} = this.state;

4 return(

5 <div className = "App">

6 <form>

7 <input

8 type = "text"

9 value = {searchText}

10 onChange = {this.onSearchChange}

11 ></input>

12 </form>

13 </div>

14 )

15 }

16 }

现在输入框的单项数据流循环是自包含的,组件内部状态是输入框的唯一数据来源

拆分组件

用于搜索的输入组件和一个用于展示的列表组件

 1   class App extends Componet{

2 render(){

3 const {searchText,list} = this.state;

4 return(

5 <div className = "App">

6 <Search />

7 <Table />

8 </div>

9 )

10 }

11 }

在组件传递属性并在组件中使用,App组件需要传递本地状态 state 托管的属性和它自己的类方法

 1   class App extends Component{

2 render(){

3 const {searchText,list} = this.state;

4 return(

5 <div>

6 <Search

7 value = {searchText}

8 onChange = {this.onSearchChange} />

9 <Table

10 list = {list}

11 pattern = {searchText}

12 onDismiss = {this.onDismiss} />

13 </div>

14 )

15 }

16 }

Search组件

 1   class Search extends Component{

2 render(){

3 const {value,onChange} = this.props;

4 return(

5 <form>

6 <input

7 type = "text"

8 value = {value}

9 onChange = {onChange} />

10 </form>

11 )

12 }

13 }

Table组件

 1   class Table extends Component{

2 render(){

3 const {list,pattern.onDismiss} = this.props;

4 return(

5 <div>

6 {list.filter(isSearched(pattern)).map(item =>

7 <div key = {item.objectID}>

8 <span><a href = {item.url}>{item.title}</a></span>

9 <span>{item.title}</span>

10 <soan>{item.points}</span>

11 <span>{item.num_comments}</span>

12 <button onClick ={() => onDismiss(item.objectID)}>

13 Dismiss

14 </button>

15 </div>

16 )}

17 </div>

18 )

19 }

20 }

可组合组件

props 对象中还有一个小小的属性可以供使用: children 属性.通过这个属性可以将元素从上层传递到组件中,这些元素对组件来说是未知的,但是却为组件互相结合提供了可能性、 下例中,将一个文本作为子元素传递到Search组件中

 1   class App extends Component{

2 render(){

3 const {searchText,list} = user;

4 return(

5 <div>

6 <Search

7 value = {searchText}

8 onChange = {this.onSearchChange} />

9 )

10 }

11 }

Search 组件可以从 props 对象中解构出 children 属性,就可以指定它应该在哪里显示

 1 class Search extends Component{

2 render(){

3 const {value,onChange,children} = this.props;

4 return(

5 <form>

6 {children}

7 <input

8 type = "text"

9 value = {value}

10 onChange = {onChange} />

11 }

12 </form>

13 )

14 }

15 }

可复用组件

可复用和可组合组件帮助理解合理的组件分层,它们是React视图层的基础

 1   class Button extends Component{

2 render(){

3 const {onClick,className,children} = this.props;

4 return(

5 <button

6 onClick = {onClick}

7 className = {className}

8 type = "button">

9 {children}

10 </button>

11 )

12 }

13 }

Button组件拥有单一可信数据源,一个Button组件可以立即重构所有button。一个Button组件统治了所有button

<Button onclick = {() => onDismiss(item.objectID)}>Dissmiss</Button>

函数式无状态组件(function stateless componenet)

这类组件就是函数,它们接受一个输入并返回一个输出。输入时props,输出就是一个普通的JSX组件实例。函数式无状态组件是函数,并且它们没有本地状态。不能通过 this.state 或者是 this.setState() 来访问或者更新状态,因为这里没有 this 对象,此外,它也没有生命周期方法。 constructor()render() 就是其中两个。 constructor 在一个组件的生命周期只执行一次,而 render() 方法只会在最开始执行一次

ES6 类组件

在类的定义中,它们继承自 React 组件。 extend 会注册所有的生命周期方法,只要在 React component API中,都可以在组件中使用。通过这种方式,可以使用 render() 方法,此外还可以通过使用 this.statethis.setState() 来存储和操作 state

把上例的Search组件重构为一个函数式无状态组件

 1 function Search(props){

2 const {value,onChange,children} = props;

3 return{

4 <form>

5 {children}<input

6 type = "text"

7 value = {value}

8 onChange = {onChange} />

9 </form>

10 }

11 }

或者将参数放在函数里面

 1 function Search({value,onChange,children}){

2 return{

3 <form>

4 {children}<input

5 type = "text"

6 value = {value}

7 onChange = {onChange} />

8 </form>

9 }

10 }

然后ES6 箭头函数一波

1 const Search = ({value,onChange,children}) =>

2 <form>

3 {children}<input

4 type = "text"

5 value = {value}

6 onChange = {onChange} />

7 </form>

如果想在ES6箭头函数写法中做些事情的话 可以这样写

 1 const Search = ({value,onChange,children}) => {

2 ​

3 //do something

4 return(

5 <form>

6 {children}<input

7 type = "text"

8 value = {value}

9 onChange = {onChange} />

10 </form>

11 )

12 }

给组件声明样式

可以复用 src/App.css 或者 src/index.css 文件

以上是 The Road to learn React书籍学习笔记(第二章) 的全部内容, 来源链接: utcz.com/z/382556.html

回到顶部