200 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			200 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| ---
 | ||
| id: 5a24c314108439a4d4036166
 | ||
| title: 组合 React 组件
 | ||
| challengeType: 6
 | ||
| forumTopicId: 301381
 | ||
| dashedName: compose-react-components
 | ||
| ---
 | ||
| 
 | ||
| # --description--
 | ||
| 
 | ||
| 随着挑战继续,将组合使用更复杂的 React 组件和 JSX,有一点需要注意。 在其它组件中渲染 ES6 风格的类组件和渲染在过去几个挑战中使用的简单组件没有什么不同。 可以在其它组件中渲染 JSX 元素、无状态功能组件和 ES6 类组件。
 | ||
| 
 | ||
| # --instructions--
 | ||
| 
 | ||
| 在代码编辑器中,`TypesOfFood` 组件已经渲染了一个名为 `Vegetables` 的组件。 此外,还有上次挑战中的 `Fruits` 组件。
 | ||
| 
 | ||
| 在 `Fruits` 中嵌套两个组件,首先 `NonCitrus`,然后是 `Citrus`, 这两个组件都已经引入。 接下来,将 `Fruits` 类组件嵌套到 `TypesOfFood` 组件中,位于 `h1` 标题元素下方和 `Vegetables` 上方。 结果应该是一系列嵌套的组件,它们使用两种不同的组件类型。
 | ||
| 
 | ||
| # --hints--
 | ||
| 
 | ||
| `TypesOfFood` 组件应该返回单个 `div` 元素。
 | ||
| 
 | ||
| ```js
 | ||
| assert(
 | ||
|   (function () {
 | ||
|     const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood));
 | ||
|     return mockedComponent.children().type() === 'div';
 | ||
|   })()
 | ||
| );
 | ||
| ```
 | ||
| 
 | ||
| `TypesOfFood` 组件应该返回 `Fruits` 组件。
 | ||
| 
 | ||
| ```js
 | ||
| assert(
 | ||
|   (function () {
 | ||
|     const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood));
 | ||
|     return mockedComponent.children().childAt(1).name() === 'Fruits';
 | ||
|   })()
 | ||
| );
 | ||
| ```
 | ||
| 
 | ||
| `Fruits` 组件应该返回 `NonCitrus` 组件和 `Citrus` 组件。
 | ||
| 
 | ||
| ```js
 | ||
| assert(
 | ||
|   (function () {
 | ||
|     const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood));
 | ||
|     return (
 | ||
|       mockedComponent.find('Fruits').children().find('NonCitrus').length ===
 | ||
|         1 &&
 | ||
|       mockedComponent.find('Fruits').children().find('Citrus').length === 1
 | ||
|     );
 | ||
|   })()
 | ||
| );
 | ||
| ```
 | ||
| 
 | ||
| `TypesOfFood` 组件应该返回 `Vegetables` 组件,且其位于 `Fruits` 组件之下。
 | ||
| 
 | ||
| ```js
 | ||
| assert(
 | ||
|   (function () {
 | ||
|     const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood));
 | ||
|     return mockedComponent.children().childAt(2).name() === 'Vegetables';
 | ||
|   })()
 | ||
| );
 | ||
| ```
 | ||
| 
 | ||
| # --seed--
 | ||
| 
 | ||
| ## --before-user-code--
 | ||
| 
 | ||
| ```jsx
 | ||
| class NonCitrus extends React.Component {
 | ||
|   render() {
 | ||
|     return (
 | ||
|       <div>
 | ||
|         <h4>Non-Citrus:</h4>
 | ||
|         <ul>
 | ||
|           <li>Apples</li>
 | ||
|           <li>Blueberries</li>
 | ||
|           <li>Strawberries</li>
 | ||
|           <li>Bananas</li>
 | ||
|         </ul>
 | ||
|       </div>
 | ||
|     );
 | ||
|   }
 | ||
| };
 | ||
| class Citrus extends React.Component {
 | ||
|   render() {
 | ||
|     return (
 | ||
|       <div>
 | ||
|         <h4>Citrus:</h4>
 | ||
|         <ul>
 | ||
|           <li>Lemon</li>
 | ||
|           <li>Lime</li>
 | ||
|           <li>Orange</li>
 | ||
|           <li>Grapefruit</li>
 | ||
|         </ul>
 | ||
|       </div>
 | ||
|     );
 | ||
|   }
 | ||
| };
 | ||
| class Vegetables extends React.Component {
 | ||
|   render() {
 | ||
|     return (
 | ||
|       <div>
 | ||
|         <h2>Vegetables:</h2>
 | ||
|         <ul>
 | ||
|           <li>Brussel Sprouts</li>
 | ||
|           <li>Broccoli</li>
 | ||
|           <li>Squash</li>
 | ||
|         </ul>
 | ||
|       </div>
 | ||
|     );
 | ||
|      }
 | ||
| };
 | ||
| ```
 | ||
| 
 | ||
| ## --after-user-code--
 | ||
| 
 | ||
| ```jsx
 | ||
| ReactDOM.render(<TypesOfFood />, document.getElementById('root'))
 | ||
| ```
 | ||
| 
 | ||
| ## --seed-contents--
 | ||
| 
 | ||
| ```jsx
 | ||
| class Fruits extends React.Component {
 | ||
|   constructor(props) {
 | ||
|     super(props);
 | ||
|   }
 | ||
|   render() {
 | ||
|     return (
 | ||
|       <div>
 | ||
|         <h2>Fruits:</h2>
 | ||
|         { /* Change code below this line */ }
 | ||
| 
 | ||
|         { /* Change code above this line */ }
 | ||
|       </div>
 | ||
|     );
 | ||
|   }
 | ||
| };
 | ||
| 
 | ||
| class TypesOfFood extends React.Component {
 | ||
|   constructor(props) {
 | ||
|      super(props);
 | ||
|   }
 | ||
|   render() {
 | ||
|     return (
 | ||
|       <div>
 | ||
|         <h1>Types of Food:</h1>
 | ||
|         { /* Change code below this line */ }
 | ||
| 
 | ||
|         { /* Change code above this line */ }
 | ||
|         <Vegetables />
 | ||
|       </div>
 | ||
|     );
 | ||
|   }
 | ||
| };
 | ||
| ```
 | ||
| 
 | ||
| # --solutions--
 | ||
| 
 | ||
| ```jsx
 | ||
| class Fruits extends React.Component {
 | ||
|   constructor(props) {
 | ||
|     super(props);
 | ||
|   }
 | ||
|   render() {
 | ||
|     return (
 | ||
|       <div>
 | ||
|         <h2>Fruits:</h2>
 | ||
|         { /* Change code below this line */ }
 | ||
|         <NonCitrus />
 | ||
|         <Citrus />
 | ||
|         { /* Change code above this line */ }
 | ||
|       </div>
 | ||
|     )
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| class TypesOfFood extends React.Component {
 | ||
|   constructor(props) {
 | ||
|      super(props);
 | ||
|   }
 | ||
|     render() {
 | ||
|       return (
 | ||
|         <div>
 | ||
|         <h1>Types of Food:</h1>
 | ||
|           { /* Change code below this line */ }
 | ||
|           <Fruits />
 | ||
|           { /* Change code above this line */ }
 | ||
|           <Vegetables />
 | ||
|         </div>
 | ||
|       );
 | ||
|     }
 | ||
| };
 | ||
| ```
 |