Logo
Section 1 / 4

提升状态

我们已经在前面的章节中学习了使用 React 的本地状态来管理状态的基础知识,本章将深入探讨更多内容。在本节课中,我们将学习什么是状态提升(lifting state),以及如何在 React 中使用它。

导入

提升状态

我们已经在前面的章节中学习了使用 React 的本地状态来管理状态的基础知识,本章将深入探讨更多内容。在本节课中,我们将学习什么是状态提升(lifting state),以及如何在 React 中使用它。

什么是“提升状态”?

在你的应用中,只有 App 组件是一个具有状态的 ES6 组件。它在其类方法中处理了大量应用状态和逻辑。此外,我们向 Table 组件传递了许多属性,其中大多数只在 Table 组件内部使用。App 组件并不需要了解这些细节,因此排序功能可以移入 Table 组件。

将子组件中的状态从一个组件移动到另一个组件,称为“提升状态”。我们希望将那些在 App 组件中未被使用的状态,从父组件向下移动到子组件 Table 中。为了在 Table 组件中处理状态和类方法,它必须变成一个 ES6 类组件。

重构 Table 组件

从无状态函数式组件重构为 ES6 类组件非常简单。

你原来的 Table 组件作为无状态函数式组件:

1const Table = ({ 2 list, 3 sortKey, 4 isSortReverse, 5 onSort, 6 onDismiss 7}) => { 8 const sortedList = SORTS[sortKey](list); 9 const reverseSortedList = isSortReverse 10 ? sortedList.reverse() 11 : sortedList; 12 13 return( 14 ... 15 ); 16}

你现在的 Table 组件作为 ES6 类组件:

1class Table extends Component { 2 3 render() { 4 const { 5 list, 6 sortKey, 7 isSortReverse, 8 onSort, 9 onDismiss 10 } = this.props; 11 12 const sortedList = SORTS[sortKey](list); 13 const reverseSortedList = isSortReverse 14 ? sortedList.reverse() 15 : sortedList; 16 17 return( 18 ... 19 ); 20 } 21}

由于你希望在组件中处理状态和方法,必须添加构造函数和初始状态。

1class Table extends Component { 2 3 constructor(props) { 4 super(props); 5 6 this.state = {}; 7 } 8 9 render() { 10 ... 11 } 12}

现在你可以将原本在 App 组件中处理的与排序相关的状态和类方法,移入 Table 组件中。

1class Table extends Component { 2 constructor(props) { 3 super(props); 4 5 this.state = { 6 sortKey: 'NONE', 7 isSortReverse: false, 8 }; 9 10 this.onSort = this.onSort.bind(this); 11 } 12 13 onSort(sortKey) { 14 const isSortReverse = this.state.sortKey === sortKey && 15 !this.state.isSortReverse; 16 17 this.setState({ sortKey, isSortReverse }); 18 } 19 20 render() { 21 ... 22 } 23}

别忘了从 App 组件中移除已迁移的状态和 onSort() 类方法。

1class App extends Component { 2 _isMounted = false; 3 4 constructor(props) { 5 super(props); 6 7 this.state = { 8 results: null, 9 searchKey: '', 10 searchTerm: DEFAULT_QUERY, 11 error: null, 12 isLoading: false, 13 }; 14 15 this.setSearchTopStories = this.setSearchTopStories.bind(this); 16 this.fetchSearchTopStories = this.fetchSearchTopStories.bind(this); 17 this.onDismiss = this.onDismiss.bind(this); 18 this.onSearchSubmit = this.onSearchSubmit.bind(this); 19 this.onSearchChange = this.onSearchChange.bind(this); 20 this.needsToSearchTopStories = this.needsToSearchTopStories.bind(this); 21 } 22 23 ... 24 25}

让 Table 组件更轻量

为此,我们将从 App 组件传递给它的 props 移动到内部处理,因为它们现在由 Table 组件自行管理。

1class App extends Component { 2 3 ... 4 5 render() { 6 const { 7 searchTerm, 8 results, 9 searchKey, 10 error, 11 isLoading 12 } = this.state; 13 14 ... 15 16 return ( 17 <div className="page"> 18 ... 19 { error 20 ? <div className="interactions"> 21 <p>Something went wrong.</p> 22 </div> 23 : <Table 24 list={list} 25 onDismiss={this.onDismiss} 26 /> 27 } 28 ... 29 </div> 30 ); 31 } 32}

现在在你的 Table 组件中,可以使用内部的 onSort() 方法和内部的 Table 状态。

1class Table extends Component { 2 3 ... 4 5 render() { 6 const { 7 list, 8 onDismiss 9 } = this.props; 10 11 const { 12 sortKey, 13 isSortReverse, 14 } = this.state; 15 16 const sortedList = SORTS[sortKey](list); 17 const reverseSortedList = isSortReverse 18 ? sortedList.reverse() 19 : sortedList; 20 21 return( 22 <div className="table"> 23 <div className="table-header"> 24 <span style={{ width: '40%' }}> 25 <Sort 26 sortKey={'TITLE'} 27 onSort={this.onSort} 28 activeSortKey={sortKey} 29 > 30 Title 31 </Sort> 32 </span> 33 <span style={{ width: '30%' }}> 34 <Sort 35 sortKey={'AUTHOR'} 36 onSort={this.onSort} 37 activeSortKey={sortKey} 38 > 39 Author 40 </Sort> 41 </span> 42 <span style={{ width: '10%' }}> 43 <Sort 44 sortKey={'COMMENTS'} 45 onSort={this.onSort} 46 activeSortKey={sortKey} 47 > 48 Comments 49 </Sort> 50 </span> 51 <span style={{ width: '10%' }}> 52 <Sort 53 sortKey={'POINTS'} 54 onSort={this.onSort} 55 activeSortKey={sortKey} 56 > 57 Points 58 </Sort> 59 </span> 60 <span style={{ width: '10%' }}> 61 Archive 62 </span> 63 </div> 64 { reverseSortedList.map((item) => 65 ... 66 )} 67 </div> 68 ); 69 } 70}

我们通过将功能和状态更贴近相关组件进行了一次关键重构,其他组件因此变得更轻量。再次强调,Table 组件的 API 变得更简洁,因为它内部已经处理了排序功能。

状态提升也可以反过来进行:从子组件提升到父组件,这被称为“向上提升状态”。假设你在子组件中维护本地状态,但需要在父组件中显示该状态。这时就必须将状态提升到父组件。再比如,你想在子组件的兄弟组件中显示该状态,同样需要将状态提升到父组件。父组件负责管理本地状态,并将其暴露给两个子组件使用。

练习:

高级 React 组件

重新回顾:setState()