fix(i18n): update Chinese translation of react (#38657)

Co-authored-by: Zhicheng Chen <chenzhicheng@dayuwuxian.com>
This commit is contained in:
ZhichengChen
2020-09-18 00:13:42 +08:00
committed by GitHub
parent 4605ec5ec6
commit 6021a32de9
47 changed files with 2153 additions and 601 deletions

View File

@ -3,30 +3,35 @@ id: 5a24c314108439a4d403616e
title: Access Props Using this.props
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用this.props访问道具
forumTopicId: 301375
localeTitle: 使用 this.props 访问 Props
---
## Description
<section id="description">最后几个挑战涵盖了将道具传递给子组件的基本方法。但是如果你传递道具的子组件是ES6类组件而不是无状态功能组件呢 ES6类组件使用稍微不同的约定来访问props。无论何时在您自己引用类组件时都使用<code>this</code>关键字。一类组件中访问的道具,你前言您使用与访问它的代码<code>this</code> 。例如如果ES6类组件具有名为<code>data</code>的prop则在JSX中编写<code>{this.props.data}</code></section>
<section id='description'>
前几项挑战涵盖了将 props 传递给子组件的基本方法。但是,倘若接收 prop 的子组件不是无状态函数组件,而是一个 ES6 类组件又当如何呢ES6 类组件访问 props 的方法略有不同。
任何时候,只要引用类组件本身,就要使用<code>this</code>关键字。要访问类组件中的 props你需要在在访问它的代码前面添加<code>this</code>。例如,如果 ES6 类组件有一个名为<code>data</code>的 prop你可以在 JSX 中这样写:<code>{this.props.data}</code>
</section>
## Instructions
<section id="instructions">在父组件<code>ResetPassword</code>呈现<code>ReturnTempPassword</code>组件的实例。在这里,给<code>ReturnTempPassword</code>一个<code>tempPassword</code>的prop并为它<code>tempPassword</code>一个至少8个字符长的字符串的值。在子项<code>ReturnTempPassword</code> ,访问<code>strong</code>标记内的<code>tempPassword</code> prop以确保用户看到临时密码。 </section>
<section id='instructions'>
在父组件<code>ResetPassword</code>中渲染<code>ReturnTempPassword</code>组件的一个实例。在这里,为<code>ReturnTempPassword</code>提供一个<code>tempPassword</code>prop并赋值给 prop 一个长度至少为 8 个字符的字符串。在子组件<code>ReturnTempPassword</code>中,访问<code>strong</code>标签中的<code>tempPassword</code>prop以确保用户看到临时密码。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>ResetPassword</code>组件应返回单个<code>div</code>元素。
- text: <code>ResetPassword</code>组件应返回单个<code>div</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ResetPassword)); return mockedComponent.children().type() === 'div'; })());
- text: <code>ResetPassword</code>的第四个子<code>ResetPassword</code>应该是<code>ReturnTempPassword</code>组件。
- text: <code>ResetPassword</code>的第四个子组件应该是<code>ReturnTempPassword</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ResetPassword)); return mockedComponent.children().childAt(3).name() === 'ReturnTempPassword'; })());
- text: <code>ReturnTempPassword</code>组件应该有一个名为<code>tempPassword</code>的prop
- text: <code>ReturnTempPassword</code>组件应该有一个名为<code>tempPassword</code>的属性
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ResetPassword)); return mockedComponent.find('ReturnTempPassword').props().tempPassword; })());
- text: <code>ReturnTempPassword</code>的<code>tempPassword</code>道具应该等于至少<code>8</code>字符的字符串
- text: <code>ReturnTempPassword</code>组件的<code>tempPassword</code>prop 值应该是一个字符串,其长度至少<code>8</code>。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ResetPassword)); const temp = mockedComponent.find('ReturnTempPassword').props().tempPassword; return typeof temp === 'string' && temp.length >= 8; })());
- text: <code>ReturnTempPassword</code>组件应显示您在<code>strong</code>标记内作为<code>tempPassword</code>支柱创建的密码
- text: <code>ReturnTempPassword</code>组件应显示作为<code>tempPassword</code>prop 创建的密码,并且密码显示在<code>strong</code>标签中
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ResetPassword)); return mockedComponent.find('strong').text() === mockedComponent.find('ReturnTempPassword').props().tempPassword; })());
```
@ -73,7 +78,6 @@ class ResetPassword extends React.Component {
);
}
};
```
</div>
@ -83,7 +87,7 @@ class ResetPassword extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<ResetPassword />, document.getElementById('root'))
```
</div>
@ -93,8 +97,40 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class ReturnTempPassword extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<p>Your temporary password is: <strong>{this.props.tempPassword}</strong></p>
</div>
);
}
};
class ResetPassword extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h2>Reset Password</h2>
<h3>We've generated a new temporary password for you.</h3>
<h3>Please reset this password from your account settings ASAP.</h3>
{ /* change code below this line */ }
<ReturnTempPassword tempPassword="serrPbqrPnzc" />
{ /* change code above this line */ }
</div>
);
}
};
```
/section>
</section>

View File

@ -3,15 +3,20 @@ id: 5a24bbe0dba28a8d3cbd4c5e
title: Add Comments in JSX
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 在JSX中添加注释
forumTopicId: 301376
localeTitle: 在 JSX 中添加注释
---
## Description
<section id="description"> JSX是一种可以编译成有效JavaScript的语法。有时为了便于阅读您可能需要在代码中添加注释。像大多数编程语言一样JSX有自己的方法来做到这一点。要将注释放在JSX中可以使用语法<code>{/* */}</code>来包含注释文本。 </section>
<section id='description'>
JSX 是一种可以编译成有效 JavaScript 的语法。有时为了便于阅读你可能需要在代码中添加注释。像大多数编程语言一样JSX 也有自己的方法来实现这一点。
要将注释放在 JSX 中,可以使用<code>{/* */}</code>语法来包裹注释文本。
</section>
## Instructions
<section id="instructions">代码编辑器的JSX元素与您在上一个挑战中创建的元素类似。在提供的<code>div</code>元素中的某处添加注释,而不修改现有的<code>h1</code><code>p</code>元素。 </section>
<section id='instructions'>
代码编辑器中的 JSX 元素与你在上一个挑战中创建的元素类似。在提供的<code>div</code>元素中的某处添加注释,而不修改现有的<code>h1</code><code>p</code>元素。
</section>
## Tests
<section id='tests'>
@ -19,14 +24,15 @@ localeTitle: 在JSX中添加注释
```yml
tests:
- text: 常量<code>JSX</code>应该返回一个<code>div</code>元素。
testString: 'assert(JSX.type === "div", "The constant <code>JSX</code> should return a <code>div</code> element.");'
- text: <code>div</code>应包含一个<code>h1</code>标作为第一个元素。
testString: 'assert(JSX.props.children[0].type === "h1", "The <code>div</code> should contain an <code>h1</code> tag as the first element.");'
testString: assert(JSX.type === 'div');
- text: <code>div</code>应包含一个<code>h1</code>标作为第一个元素。
testString: assert(JSX.props.children[0].type === 'h1');
- text: <code>div</code>应该包含一个<code>p</code>标签作为第二个元素。
testString: 'assert(JSX.props.children[1].type === "p", "The <code>div</code> should contain a <code>p</code> tag as the second element.");'
- text: <code>JSX</code>应该包含一条评论
testString: 'getUserInput => assert(getUserInput("index").includes("/*") && getUserInput("index").includes("*/"), "The <code>JSX</code> should include a comment.");'
testString: assert(JSX.props.children[1].type === 'p');
- text: 当前的 <code>h1</code> 和 <code>p</code> 元素不能被修改
testString: assert(JSX.props.children[0].props.children === 'This is a block of JSX' && JSX.props.children[1].props.children === 'Here\'s a subtitle');
- text: <code>JSX</code>应该包含一个注释。
testString: assert(/<div>[\s\S]*{\s*\/\*[\s\S]*\*\/\s*}[\s\S]*<\/div>/.test(code));
```
</section>
@ -43,7 +49,6 @@ const JSX = (
<p>Here's a subtitle</p>
</div>
);
```
</div>
@ -53,7 +58,7 @@ const JSX = (
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(JSX, document.getElementById('root'))
```
</div>
@ -63,8 +68,14 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const JSX = (
<div>
<h1>This is a block of JSX</h1>
{ /* this is a JSX comment */ }
<p>Here's a subtitle</p>
</div>);
```
/section>
</section>

View File

@ -3,28 +3,34 @@ id: 5a24c314108439a4d403617e
title: Add Event Listeners
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 添加事件听器
forumTopicId: 301377
localeTitle: 添加事件听器
---
## Description
<section id="description"> <code>componentDidMount()</code>方法也是附加您需要为特定功能添加的任何事件侦听器的最佳位置。 React提供了一个合成事件系统它包装了浏览器中的本机事件系统。这意味着无论用户的浏览器如何合成事件系统的行为都完全相同 - 即使本机事件在不同浏览器之间的行为可能不同。您已经使用了一些合成事件处理程序,如<code>onClick()</code> 。 React的合成事件系统非常适合用于您在DOM元素上管理的大多数交互。但是如果要将事件处理程序附加到文档或窗口对象则必须直接执行此操作。 </section>
<section id='description'>
<code>componentDidMount()</code>方法也是添加特定功能所需的任何事件监听器的最佳位置。React 提供了一个合成事件系统,它将本地事件系统封装在浏览器中。这意味着,不管用户的浏览器如何,合成事件系统的行为都完全相同--即使不同浏览器之间的本地事件的行为可能不同。
你已经使用了一些合成事件处理程序,如<code>onClick()</code>。React 的合成事件系统非常适合用于你在 DOM 元素上管理的大多数交互。但是,如果要将事件处理程序附加到 document 或 window 对象,则必须直接执行此操作。
</section>
## Instructions
<section id="instructions"><code>componentDidMount()</code>方法中为<code>keydown</code>事件附加事件侦听器,并让这些事件触发回调<code>handleKeyPress()</code> 。您可以使用<code>document.addEventListener()</code> ,它将事件(在引号中)作为第一个参数,将回调作为第二个参数。然后,在<code>componentWillUnmount()</code> ,删除此相同的事件侦听器。您可以将相同的参数传递给<code>document.removeEventListener()</code> 。在卸载和销毁之前使用此生命周期方法对React组件进行任何清理是一种很好的做法。删除事件侦听器就是一个这样的清理操作的示例。 </section>
<section id='instructions'>
<code>componentDidMount()</code>方法中为<code>keydown</code>事件添加事件监听器,并让这些事件触发回调<code>handleKeyPress()</code>。你可以使用<code>document.addEventListener()</code>,它将事件(用引号括起来)作为第一个参数,将回调作为第二个参数。
然后,在<code>componentWillUnmount()</code>中移除相同的事件监听器。你可以把相同的参数传递给<code>document.removeEventListener()</code>。在卸载和销毁 React 组件之前,最好使用这种生命周期方法对它们进行清理。移除事件监听器就是这样一个清理操作的例子。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyComponent</code>应该呈现一个包含<code>h1</code>标的<code>div</code>元素。
- text: <code>MyComponent</code>应该渲染一个包含<code>h1</code>标的<code>div</code>元素。
testString: assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find('div').children().find('h1').length === 1; })());
- text: keydown侦听器应附加到<code>componentDidMount</code>的文档
- text: 应该在<code>componentDidMount</code>中将 keydown 事件监听添加到到 document 上
testString: assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const didMountString = mockedComponent.instance().componentDidMount.toString(); return new RegExp('document\.addEventListener(.|\n|\r)+keydown(.|\n|\r)+this\.handleKeyPress').test(didMountString); })());
- text: 应该<code>componentWillUnmount</code>的文档中删除keydown侦听器
- text: 应该<code>componentWillUnmount</code>中将 document 上的 keydown 事件监听移除
testString: assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const willUnmountString = mockedComponent.instance().componentWillUnmount.toString(); return new RegExp('document\.removeEventListener(.|\n|\r)+keydown(.|\n|\r)+this\.handleKeyPress').test(willUnmountString); })());
- text: 组件安装完成后,按<code>enter</code>应更新其状态和渲染<code>h1</code>标签。
- text: 一旦组件装载完毕,按<code>enter</code>应该会更新其 state 并渲染<code>h1</code>标签。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const beforeState = mockedComponent.state(''message''); const beforeText = mockedComponent.find(''h1'').text(); const pressEnterKey = () => { mockedComponent.instance().handleKeyPress({ keyCode: 13 }); return waitForIt(() => { mockedComponent.update(); return { state: mockedComponent.state(''message''), text: mockedComponent.find(''h1'').text()}; });}; const afterKeyPress = await pressEnterKey(); assert(beforeState !== afterKeyPress.state && beforeText !== afterKeyPress.text); }; '
```
@ -41,7 +47,7 @@ class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
message: "
message: ''
};
this.handleEnter = this.handleEnter.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
@ -72,7 +78,6 @@ class MyComponent extends React.Component {
);
}
};
```
</div>
@ -82,7 +87,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -92,8 +97,44 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
message: ''
};
this.handleKeyPress = this.handleKeyPress.bind(this);
this.handleEnter = this.handleEnter.bind(this); }
componentDidMount() {
// change code below this line
document.addEventListener('keydown', this.handleKeyPress);
// change code above this line
}
componentWillUnmount() {
// change code below this line
document.removeEventListener('keydown', this.handleKeyPress);
// change code above this line
}
handleEnter() {
this.setState({
message: this.state.message + 'You pressed the enter key! '
});
}
handleKeyPress(event) {
if (event.keyCode === 13) {
this.handleEnter();
}
}
render() {
return (
<div>
<h1>{this.state.message}</h1>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,30 +3,35 @@ id: 5a24c314108439a4d4036182
title: Add Inline Styles in React
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 在React中添加内联样式
forumTopicId: 301378
localeTitle: 在 React 中添加内联样式
---
## Description
<section id="description">您可能已经注意到在上一个挑战中除了设置为JavaScript对象的<code>style</code>属性之外还有HTML内联样式的其他几种语法差异。首先某些CSS样式属性的名称使用驼峰大小写。例如最后一个挑战使用<code>fontSize</code>而不是<code>font-size</code>设置<code>font-size</code> 。像<code>font-size</code>这样的连字符是JavaScript对象属性的无效语法因此React使用驼峰大小写。通常任何带连字符的样式属性都是使用JSX中的camel case编写的。除非另有说明否则假定所有属性值长度单位<code>height</code> <code>width</code><code>fontSize</code> )均为<code>px</code> 。例如,如果要使用<code>em</code> ,则将值和单位用引号括起来,如<code>{fontSize: &quot;4em&quot;}</code> 。除了默认为<code>px</code>的长度值之外,所有其他属性值都应该用引号括起来。 </section>
<section id='description'>
在上一次挑战中,你可能已经注意到,除了设置为 JavaScript 对象的<code>style</code>属性之外,与 HTML 内联样式相比React 的内联样式还有其他几个语法差异。首先,某些 CSS 样式属性的名称使用驼峰式命名。例如,最后一个挑战用<code>fontSize</code>而不是<code>font-size</code>来设置字体的大小。对于 JavaScript 对象属性来说,像<code>font-size</code>这样的连字符命名是无效的语法,所以 React 使用驼峰式命名。通常,任何连字符的 style 属性在 JSX 中都是使用驼峰式命名的。
除非另有规定,否则所有属性值是长度的(如<code>height</code><code>width</code><code>fontSize</code>)其单位都假定为<code>px</code>。例如,如果要使用<code>em</code>,可以用引号将值和单位括起来,例如<code>{fontSize: "4em"}</code>。除了默认为<code>px</code>的长度值之外,所有其他属性值都应该用引号括起来。
</section>
## Instructions
<section id="instructions">如果您有大量样式,则可以将样式<code>object</code>分配给常量以保持代码的有序性。取消注释<code>styles</code>常量并声明具有三个样式属性及其值的<code>object</code> 。给<code>div</code>一个颜色为<code>&quot;purple&quot;</code> ,字体大小为<code>40</code> ,边框为<code>&quot;2px solid purple&quot;</code> 。然后将<code>style</code>属性设置为等于<code>styles</code>常量。 </section>
<section id='instructions'>
如果你有大量样式,你可以将 style<code>对象</code>分配给一个常量,以保持代码的组织有序。取消对<code>styles</code>常量的注释,并声明具有三个样式属性及对应值的<code>对象</code>。使<code>div</code>的文字颜色为<code>"purple"</code>、字号为<code>40</code>、边框为<code>"2px solid purple"</code>。然后设置<code>style</code>属性,使其等于<code>styles</code>常量。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>styles</code>变量应该是具有三个属性的<code>object</code>
- text: <code>styles</code>变量应该是具有三个属性的<code>对象</code>。
testString: assert(Object.keys(styles).length === 3);
- text: <code>styles</code>变量的<code>color</code>属性应设置为<code>purple</code>的值
- text: <code>styles</code>变量的<code>color</code>属性应设置为<code>purple</code>。
testString: assert(styles.color === 'purple');
- text: <code>styles</code>变量应该将<code>fontSize</code>属性设置为<code>40</code>
- text: <code>styles</code>变量应该将<code>fontSize</code>属性设置为<code>40</code>。
testString: assert(styles.fontSize === 40);
- text: <code>styles</code>变量应该将<code>border</code>属性设置为<code>2px solid purple</code>的值
- text: <code>styles</code>变量<code>border</code>属性应该设置为<code>2px solid purple</code>。
testString: assert(styles.border === "2px solid purple");
- text: 组件应呈现<code>div</code>元素。
- text: 组件应该渲染一个<code>div</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.shallow(React.createElement(Colorful)); return mockedComponent.type() === 'div'; })());
- text: <code>div</code>元素的样式应该由<code>styles</code>对象定义。
testString: assert((function() { const mockedComponent = Enzyme.shallow(React.createElement(Colorful)); return (mockedComponent.props().style.color === "purple" && mockedComponent.props().style.fontSize === 40 && mockedComponent.props().style.border === "2px solid purple"); })());
@ -41,6 +46,7 @@ tests:
<div id='jsx-seed'>
```jsx
// const styles =
// change code above this line
class Colorful extends React.Component {
@ -62,7 +68,7 @@ class Colorful extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<Colorful />, document.getElementById('root'))
```
</div>
@ -72,8 +78,24 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const styles = {
color: "purple",
fontSize: 40,
border: "2px solid purple"
};
// change code above this line
class Colorful extends React.Component {
render() {
// change code below this line
return (
<div style={styles}>Style Me!</div>
// change code above this line
);
}
};
```
/section>
</section>

View File

@ -3,26 +3,34 @@ id: 5a24c314108439a4d4036174
title: Bind 'this' to a Class Method
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 将'this'绑定到方法
forumTopicId: 301379
localeTitle: 将 this 绑定到 Class 方法
---
## Description
<section id="description">除了设置和更新<code>state</code> ,您还可以为组件类定义方法。类方法通常需要使用<code>this</code>关键字,以便它可以访问方法范围内的类(例如<code>state</code><code>props</code> )上的属性。有几种方法可以让您的类方法访问<code>this</code> 。一个常用的方法是显式绑定<code>this</code>所以在构造<code>this</code>组件已初始化变为绑定到类方法。您可能已经注意到最后一个挑战使用<code>this.handleClick = this.handleClick.bind(this)</code>作为构造函数中的<code>handleClick</code>方法。然后,当您在类方法中调用类似<code>this.setState()</code>的函数时, <code>this</code>引用该类,并且不会被<code>undefined</code><strong>注意:</strong> <code>this</code>关键字是JavaScript中最令人困惑的方面之一但它在React中起着重要作用。虽然这里的行为是完全正常的但这些课程并不是<code>this</code>进行深入审查的地方,所以如果上述内容令人困惑,请参考其他课程! </section>
<section id='description'>
除了设置和更新<code>state</code>之外,你还可以为组件类定义方法。类方法通常需要使用<code>this</code>关键字,以便它可以访问方法中类的属性(例如<code>state</code><code>props </code>)。有几种方法可以让你的类方法访问<code>this</code>
一种常见的方法是在构造函数中显式地绑定<code>this</code>,这样当组件初始化时,<code>this</code>就会绑定到类方法。你可能已经注意到上一个挑战使用了<code>this.handleClick = this.handleClick.bind(this)</code>用于其在构造函数中的<code>handleClick</code>方法。然后,当你在类方法中调用像<code>this.setState()</code>这样的函数时,<code>this</code>指的是这个类,而不是<code>undefined</code>
<strong>注意:</strong>&nbsp;<code>this</code>关键字是 JavaScript 中最令人困惑的方面之一,但它在 React 中扮演着重要的角色。虽然它的行为在这里是完全正常的,但是这些课程并不深入研究<code>this</code>,所以如果以上内容令你感到困惑,请参考其他课程!
</section>
## Instructions
<section id="instructions">代码编辑器具有与组件<code>state</code>保持跟踪的项目计数。它还有一个方法,允许您增加此项目计数。但是,该方法不起作用,因为它使用未定义的<code>this</code>关键字。通过明确地结合修复它<code>this</code><code>addItem()</code>在组件的构造方法。接下来将单击处理程序添加到render方法中的<code>button</code>元素。当按钮收到click事件时它应该触发<code>addItem()</code>方法。请记住,传递给<code>onClick</code>处理程序的方法需要花括号因为它应该直接解释为JavaScript。完成上述步骤后您应该可以单击按钮并查看HTML中的项目计数增量。 </section>
<section id='instructions'>
代码编辑器有一个带有<code>state</code>的组件,用于跟踪项目计数。它还有一个方法,允许你增加此项目计数。但是,该方法不起作用,因为它使用了未定义的<code>this</code>关键字。可以通过将<code>this</code>显式绑定到组件构造函数中的<code>addItem()</code>方法来修复它。
接下来,向 render 方法中的<code>button</code>元素添加一个单击处理程序。当按钮接收到单击事件时,它应该触发<code>addItem()</code>方法。记住,传递给<code>onClick</code>处理程序的方法需要使用花括号,因为它应该直接被解释为 JavaScript。
完成上述步骤后,你应该可以单击按钮并查看 HTML 中的项目计数增量。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyComponent</code>应返回一个<code>div</code>元素,按顺序包两个元素,一个按钮和一个<code>h1</code>元素。
- text: <code>MyComponent</code>应返回<code>div</code>元素,该元素按顺序包两个元素,一个按钮和一个<code>h1</code>元素。
testString: assert(Enzyme.mount(React.createElement(MyComponent)).find('div').length === 1 && Enzyme.mount(React.createElement(MyComponent)).find('div').childAt(0).type() === 'button' && Enzyme.mount(React.createElement(MyComponent)).find('div').childAt(1).type() === 'h1');
- text: '<code>MyComponent</code>的状态应使用键值对<code>{ itemCount: 0 }</code>初始化。'
- text: '<code>MyComponent</code>的 state 应该使用键值对<code>{ itemCount: 0 }</code>进行初始化。'
testString: 'assert(Enzyme.mount(React.createElement(MyComponent)).state(''text'') === ''Hello'');'
- text: 单击<code>button</code>元素应该运行<code>addItem</code>方法并将状态<code>itemCount</code>递增<code>1</code>
- text: 单击<code>button</code>元素应该运行<code>addItem</code>方法,并使 state<code>itemCount</code>的计数增加<code>1</code>。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ text: ''Hello'' }); return waitForIt(() => mockedComponent.state(''text'')); }; const second = () => { mockedComponent.find(''button'').simulate(''click''); return waitForIt(() => mockedComponent.state(''text'')); }; const firstValue = await first(); const secondValue = await second(); assert(firstValue === ''Hello'' && secondValue === ''You clicked!''); };'
```
@ -39,15 +47,15 @@ class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
itemCount: 0
text: "Hello"
};
// change code below this line
// change code above this line
}
addItem() {
handleClick() {
this.setState({
itemCount: this.state.itemCount + 1
text: "You clicked!"
});
}
render() {
@ -56,12 +64,11 @@ class MyComponent extends React.Component {
{ /* change code below this line */ }
<button>Click Me</button>
{ /* change code above this line */ }
<h1>Current Item Count: {this.state.itemCount}</h1>
<h1>{this.state.text}</h1>
</div>
);
}
};
```
</div>
@ -71,7 +78,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -81,8 +88,30 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "Hello"
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
text: "You clicked!"
});
}
render() {
return (
<div>
<button onClick = {this.handleClick}>Click Me</button>
<h1>{this.state.text}</h1>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,30 +3,35 @@ id: 5a24c314108439a4d4036189
title: Change Inline CSS Conditionally Based on Component State
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 有条件地改内联CSS基于组件状态
forumTopicId: 301380
localeTitle: 根据组件状态有条件地改内联 CSS
---
## Description
<section id="description">此时您已经看到了条件渲染的几个应用程序以及内联样式的使用。这是另外一个结合了这两个主题的例子。您还可以根据React组件的状态有条件地呈现CSS。要执行此操作请检查条件如果满足该条件则修改在render方法中分配给JSX元素的样式对象。这个范例很重要因为它是通过直接修改DOM元素来应用样式的更传统方法的一种戏剧性转变例如jQuery非常常见。在该方法中您必须跟踪元素何时更改并直接处理实际操作。跟踪更改可能变得很困难可能会使您的UI无法预测。根据条件设置样式对象时您将描述UI应如何看作应用程序状态的函数。有明确的信息流只能向一个方向移动。使用React编写应用程序时这是首选方法。 </section>
<section id='description'>
此时,你已经看到了一些条件渲染的应用程序和内联样式的使用。这里还有一个将这两个主题结合在一起的例子。你也可以根据 React 组件的 state 有条件地渲染 CSS。要执行此操作请检查条件如果满足该条件则修改在 render 方法中分配给 JSX 元素的样式对象。
这个范例对于更加容易理解,因为相比传统的通过直接修改 DOM 元素来应用样式的方法(这在 jQuery 中非常常见),这种方法是一个戏剧性的转变。在传统方法中,你必须跟踪元素何时发生变化,并直接处理实际操作,这使得跟踪变化变得很困难,也可能会让你的用户界面变得不可预测。当你根据一个条件设置一个样式对象时,你描述了 UI 作为应用程序的状态函数应当如何展现。如此便有一个清晰的单向流动的信息流。这是使用 React 编写应用程序时的首选方法。
</section>
## Instructions
<section id="instructions">代码编辑器有一个简单的受控输入组件带有样式边框。如果用户在输入框中键入超过15个字符的文本则希望将此边框设置为红色。添加条件以检查此情况如果条件有效则将输入边框样式设置为<code>3px solid red</code> 。您可以通过在输入中输入文本来尝试。 </section>
<section id='instructions'>
代码编辑器有一个简单的带有边框样式的受控 input 组件。如果用户在输入框中键入超过 15 个字符的文本,你希望将此边框变成红色。添加一个条件来检查这一点,如果条件有效,则将 input 的边框样式设置为<code>3px solid red</code>。你可以通过在 input 中输入文本来尝试。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>GateKeeper</code>组件应该呈现<code>div</code>元素。
- text: <code>GateKeeper</code>组件应该渲染一个de>div</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(GateKeeper)); return mockedComponent.find('div').length === 1; })());
- text: 应使用设置为空字符串的状态键<code>input</code>初始化<code>GateKeeper</code>组件
- text: <code>GateKeeper</code>组件应使用设置为空字符串的 state <code>input</code>进行初始化。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(GateKeeper)); return mockedComponent.state().input === ''; })());
- text: <code>GateKeeper</code>组件应呈现<code>h3</code>标记和<code>input</code>标
- text: <code>GateKeeper</code>组件应该渲染一个<code>h3</code>标签和一个<code>input</code>标
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(GateKeeper)); return mockedComponent.find('h3').length === 1 && mockedComponent.find('input').length === 1; })());
- text: <code>input</code>标记最初应为<code>border</code>属性的<code>1px solid black</code>样式
- text: <code>input</code>标<code>border</code>属性的样式应该初始化为<code>1px solid black</code>。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(GateKeeper)); return mockedComponent.find('input').props().style.border === '1px solid black'; })());
- text: 如果状态中的输入值超过15个字符则<code>input</code>标记应使用<code>3px solid red</code>边框进行样式设置
- text: 如果 state 中 input 的值超过 15 个字符,则 <code>input</code> 标签的 border 样式应为<code>3px solid red</code>。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const mockedComponent = Enzyme.mount(React.createElement(GateKeeper)); const simulateChange = (el, value) => el.simulate(''change'', {target: {value}}); let initialStyle = mockedComponent.find(''input'').props().style.border; const state_1 = () => { mockedComponent.setState({input: ''this is 15 char'' }); return waitForIt(() => mockedComponent.find(''input'').props().style.border )}; const state_2 = () => { mockedComponent.setState({input: ''A very long string longer than 15 characters.'' }); return waitForIt(() => mockedComponent.find(''input'').props().style.border )}; const style_1 = await state_1(); const style_2 = await state_2(); assert(initialStyle === ''1px solid black'' && style_1 === ''1px solid black'' && style_2 === ''3px solid red''); }; '
```
@ -39,11 +44,12 @@ tests:
<div id='jsx-seed'>
```jsx
class GateKeeper extends React.Component {
constructor(props) {
super(props);
this.state = {
input: "
input: ''
};
this.handleChange = this.handleChange.bind(this);
}
@ -69,7 +75,6 @@ class GateKeeper extends React.Component {
);
}
};
```
</div>
@ -79,7 +84,7 @@ class GateKeeper extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<GateKeeper />, document.getElementById('root'))
```
</div>
@ -89,8 +94,38 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class GateKeeper extends React.Component {
constructor(props) {
super(props);
this.state = {
input: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ input: event.target.value })
}
render() {
let inputStyle = {
border: '1px solid black'
};
if (this.state.input.length > 15) {
inputStyle.border = '3px solid red';
};
return (
<div>
<h3>Don't Type Too Much:</h3>
<input
type="text"
style={inputStyle}
value={this.state.input}
onChange={this.handleChange} />
</div>
);
}
};
```
/section>
</section>

View File

@ -3,28 +3,33 @@ id: 5a24c314108439a4d4036166
title: Compose React Components
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 撰写反应组件
forumTopicId: 301381
localeTitle: 组合 React 组件
---
## Description
<section id="description">随着挑战继续使用更复杂的组合与React组件和JSX有一点需要注意。在其他组件中渲染ES6样式类组件与渲染您在最后几个挑战中使用的简单组件没有什么不同。您可以在其他组件中呈现JSX元素无状态功能组件和ES6类组件。 </section>
<section id='description'>
随着挑战继续,我们将组合使用更复杂的 React 组件和 JSX有一点需要注意。在其他组件中渲染 ES6 风格的类组件和渲染你在过去几个挑战中使用的简单组件没有什么不同。你可以在其他组件中渲染 JSX 元素、无状态功能组件和 ES6 类组件。
</section>
## Instructions
<section id="instructions">在代码编辑器中, <code>TypesOfFood</code>组件已经在呈现一个名为<code>Vegetables</code>的组件。此外,还有最后一项挑战中的<code>Fruits</code>成分。将两种成分<code>NonCitrus</code> <code>Fruits</code> - 首先是<code>NonCitrus</code> ,然后是<code>Citrus</code> 。这两个组件都是在后台为您提供的。接下来,将<code>Fruits</code>类组件嵌入到<code>TypesOfFood</code>组件中,位于<code>h1</code>标题下方和<code>Vegetables</code>上方。结果应该是一系列嵌套组件,它们使用两种不同的组件类型。 </section>
<section id='instructions'>
在代码编辑器中,<code>TypesOfFood</code>组件已经渲染了一个名为<code>Vegetables</code>的组件。此外,还有上次挑战中的<code>Fruits</code>组件。
<code>Fruits</code>中嵌套两个组件,首先<code>NonCitrus</code>,然后是<code>Citrus</code>,这两个组件都是在后台为你提供的。接下来,将<code>Fruits</code>类组件嵌到<code>TypesOfFood</code>组件中,位于<code>h1</code>标题下方和<code>Vegetables</code>上方。结果应该是一系列嵌套的组件,它们使用两种不同的组件类型。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>TypesOfFood</code>组件应返回单个<code>div</code>元素。
- text: <code>TypesOfFood</code>组件应返回单个<code>div</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().type() === 'div'; })());
- text: <code>TypesOfFood</code>组件应返回<code>Fruits</code>组件。
- text: <code>TypesOfFood</code>组件应返回<code>Fruits</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().childAt(1).name() === 'Fruits'; })());
- text: <code>Fruits</code>组件应返回<code>NonCitrus</code>组件和<code>Citrus</code>组件。
- text: <code>Fruits</code>组件应返回<code>NonCitrus</code>组件和<code>Citrus</code>组件。
testString: 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); })());
- text: <code>TypesOfFood</code>组件应返回<code>Fruits</code>组件下面的<code>Vegetables</code>组件。
- text: <code>TypesOfFood</code>组件应返回<code>Vegetables</code>组件,且其位于<code>Fruits</code>组件之下
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().childAt(2).name() === 'Vegetables'; })());
```
@ -69,7 +74,6 @@ class TypesOfFood extends React.Component {
);
}
};
```
</div>
@ -122,7 +126,6 @@ class Vegetables extends React.Component {
);
}
};
```
</div>
@ -131,7 +134,7 @@ class Vegetables extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<TypesOfFood />, document.getElementById('root'))
```
</div>
@ -141,8 +144,41 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
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>
);
}
};
```
/section>
</section>

View File

@ -3,15 +3,43 @@ id: 5a24bbe0dba28a8d3cbd4c5d
title: Create a Complex JSX Element
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 创建一个复杂的JSX元素
forumTopicId: 301382
localeTitle: 创建一个复杂的 JSX 元素
---
## Description
<section id="description">最后一个挑战是JSX的一个简单示例但JSX也可以代表更复杂的HTML。关于嵌套JSX的一个重要事项是它必须返回一个元素。这个父元素将包装所有其他级别的嵌套元素。例如编写为没有父包装元素的兄弟姐妹的几个JSX元素将不会转换。这是一个例子 <b>有效的JSX</b> <blockquote> &lt;DIV&gt; <br> &lt;p&gt;第一段&lt;/ p&gt; <br> &lt;p&gt;第二段&lt;/ p&gt; <br> &lt;p&gt;第3段&lt;/ p&gt; <br> &lt;/ DIV&gt; </blockquote> <b>JSX无效</b> <blockquote> &lt;p&gt;第一段&lt;/ p&gt; <br> &lt;p&gt;第二段&lt;/ p&gt; <br> &lt;p&gt;第3段&lt;/ p&gt; <br></blockquote></section>
<section id='description'>
上一个挑战是 JSX 的一个简单示例,但 JSX 也可以表示更复杂的 HTML。
关于嵌套的 JSX你需要知道的一件重要的事情那就是它必须返回单个元素。
这个父元素将包裹所有其他级别的嵌套元素。
例如几个作为兄弟元素而编写的JSX元素没有父元素包裹将不会被转换。
这里是一个示例:
<b>有效的 JSX</b>
```jsx
<div>
<p>Paragraph One</p>
<p>Paragraph Two</p>
<p>Paragraph Three</p>
</div>
```
<b>无效的 JSX</b>
```jsx
<p>Paragraph One</p>
<p>Paragraph Two</p>
<p>Paragraph Three</p>
```
</section>
## Instructions
<section id="instructions">定义一个新的常量<code>JSX</code> ,它呈现一个按顺序包含以下元素的<code>div</code> :一个<code>h1</code> ,一个<code>p</code>和一个包含三个<code>li</code>项的无序列表。您可以在每个元素中包含所需的任何文本。 <strong>注意:</strong>渲染多个这样的元素时,可以将它们全部括在括号中,但并不是严格要求的。另请注意,此挑战使用<code>div</code>标记将所有子元素包装在单个父元素中。如果删除<code>div</code> JSX将不再转换。请记住这一点因为当您在React组件中返回JSX元素时它也将适用。 </section>
<section id='instructions'>
定义一个新的常量<code>JSX</code>,渲染一个<code>div</code>,其中依次包含以下元素:
一个<code>h1</code>,一个<code>p</code>,一个包含三个<code>li</code>项的无序列表。你可以在每个元素中包含任何你想要的文本。
<strong>注意:</strong>&nbsp;当像这样渲染多个元素时,你可以把它们都用圆括号括起来,但是这并不是必须的。还请注意,此挑战使用<code>div</code>标签把所有子元素包裹在里面。如果删除<code>div</code>JSX 将不会编译这些元素。请记住这一点,因为当你在 React 组件中返回 JSX 元素时它也适用。
</section>
## Tests
<section id='tests'>
@ -22,9 +50,9 @@ tests:
testString: assert(JSX.type === 'div');
- text: <code>div</code>应该包含一个<code>p</code>标签作为第二个元素。
testString: assert(JSX.props.children[0].type === 'h1');
- text: <code>div</code>应包含<code>ul</code>标作为第三个元素。
- text: <code>div</code>应包含一个<code>ul</code>标作为第三个元素。
testString: assert(JSX.props.children[1].type === 'p');
- text: <code>div</code>应包含一个<code>h1</code>标作为第一个元素。
- text: <code>div</code>应包含一个<code>h1</code>标作为第一个元素。
testString: assert(JSX.props.children[2].type === 'ul');
- text: <code>ul</code>应该包含三个<code>li</code>元素。
testString: assert(JSX.props.children.filter(ele => ele.type === 'ul')[0].props.children.filter(ele => ele.type === 'li').length === 3);
@ -50,7 +78,7 @@ tests:
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(JSX, document.getElementById('root'))
```
</div>
@ -60,8 +88,18 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const JSX = (
<div>
<h1>Hello JSX!</h1>
<p>Some info</p>
<ul>
<li>An item</li>
<li>Another item</li>
<li>A third item</li>
</ul>
</div>);
```
/section>
</section>

View File

@ -3,26 +3,44 @@ id: 5a24c314108439a4d4036164
title: Create a Component with Composition
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用Composition创建一个Component
forumTopicId: 301383
localeTitle: 用组合的方式创建一个 React 组件
---
## Description
<section id="description">现在我们来看看如何组合多个React组件。想象一下您正在构建一个应用程序并创建了三个组件一个<code>Navbar</code> <code>Dashboard</code><code>Footer</code> 。要将这些组件组合在一起,您可以创建一个<code>App</code> <i></i>组件,它将这三个组件中的每一个都呈现为<i></i>组件。要在React组件中将组件呈现为子组件请在JSX中包含作为自定义HTML标记编写的组件名称。例如<code>render</code>方法中,您可以编写: <blockquote>回来( <br> &lt;应用&gt; <br> &lt;Navbar /&gt; <br> &lt;仪表板/&gt; <br> &lt;页脚/&gt; <br> &lt;/应用&gt; <br> </blockquote>当React遇到引用另一个组件的自定义HTML标记在此示例中包含在<code>&lt; /&gt;</code>的组件名称)时,它会在标记的位置呈现该组件的标记。这应该说明<code>App</code>组件与<code>Navbar</code> <code>Dashboard</code><code>Footer</code>之间的父/子关系。 </section>
<section id='description'>
现在我们来看看如何组合多个 React 组件。想象一下,你正在构建一个应用程序,并创建了三个组件:<code>Navbar</code><code>Dashboard</code><code>Footer</code>
要将这些组件组合在一起,你可以创建一个<code>App</code><i>父组件</i>,将这三个组件分别渲染成为<i>子组件</i>。要在 React 组件中渲染一个子组件,你需要在 JSX 中包含作为自定义 HTML 标签编写的组件名称。例如,在<code>render</code>方法中,你可以这样编写:
```jsx
return (
<App>
<Navbar />
<Dashboard />
<Footer />
</App>
)
```
当 React 遇到引用另一个组件的自定义 HTML 标签时(如本例所示,组件名称包含在<code>&lt; /&gt;</code>中),它在标签的位置渲染该组件的标签。这可以说明<code>App</code>组件和<code>Navbar</code><code>Dashboard</code>以及<code>Footer</code>之间的父子关系。
</section>
## Instructions
<section id="instructions">在代码编辑器中,有一个名为<code>ChildComponent</code>的简单功能组件和一个名为<code>ParentComponent</code>的React组件。通过在<code>ParentComponent</code>呈现<code>ChildComponent</code>将两者组合在一起。确保使用正斜杠关闭<code>ChildComponent</code>标记。 <strong>注意:</strong> <code>ChildComponent</code>是使用ES6箭头函数定义的因为这是使用React时非常常见的做法。但是要知道这只是一个功能。如果您不熟悉箭头函数语法请参阅JavaScript部分。 </section>
<section id='instructions'>
在代码编辑器中,有一个名为<code>ChildComponent</code>的简单功能组件和一个名为<code>ParentComponent</code>的 React 组件。通过在<code>ParentComponent</code>中渲染<code>ChildComponent</code>来将两者组合在一起。确保使用正斜杠关闭<code>ChildComponent</code>标签。
<strong>注意:</strong>&nbsp;<code>ChildComponent</code>是使用 ES6 的箭头函数定义的,因为这是使用 React 时非常常见的做法。但是,要知道这只是一个函数。如果你不熟悉箭头函数语法,请参阅 JavaScript 部分。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: React组件应返回单个<code>div</code>元素。
- text: React 组件应返回单个<code>div</code>元素。
testString: assert((function() { var shallowRender = Enzyme.shallow(React.createElement(ParentComponent)); return shallowRender.type() === 'div'; })());
- text: 组件应返回两个嵌套元素。
- text: 组件应返回两个嵌套元素。
testString: assert((function() { var shallowRender = Enzyme.shallow(React.createElement(ParentComponent)); return shallowRender.children().length === 2; })());
- text: 组件应将ChildComponent作为其第二个子项返回
- text: 组件的第二个子元素应该是 ChildComponent。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ParentComponent)); return mockedComponent.find('ParentComponent').find('ChildComponent').length === 1; })());
```
@ -59,7 +77,6 @@ class ParentComponent extends React.Component {
);
}
};
```
</div>
@ -69,7 +86,7 @@ class ParentComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<ParentComponent />, document.getElementById('root'))
```
</div>
@ -79,8 +96,31 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const ChildComponent = () => {
return (
<div>
<p>I am the child</p>
</div>
);
};
class ParentComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>I am the parent</h1>
{ /* change code below this line */ }
<ChildComponent />
{ /* change code above this line */ }
</div>
);
}
};
```
/section>
</section>

View File

@ -3,30 +3,37 @@ id: 5a24c314108439a4d4036179
title: Create a Controlled Form
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 创建受控表格
forumTopicId: 301384
localeTitle: 创建一个可以控制的表单
---
## Description
<section id="description">最后一个挑战表明React可以控制<code>input</code><code>textarea</code>等某些元素的内部状态这使得它们成为受控组件。这也适用于其他表单元素包括常规HTML <code>form</code>元素。 </section>
<section id='description'>
上一个挑战展示了 React 能控制某些元素的内部 state比如<code>input</code><code>textarea</code>,这使得这些元素成为受控组件。这也适用于其他表单元素,包括常规的 HTML 表单<code>form</code>元素。
</section>
## Instructions
<section id="instructions"> <code>MyForm</code>组件设置为带有提交处理程序的空<code>form</code> 。提交表单时将调用提交处理程序。我们添加了一个提交表单的按钮。您可以看到它的<code>type</code>设置为<code>submit</code>表明它是控制表单的按钮。在<code>form</code>添加<code>input</code>元素并设置其<code>value</code><code>onChange()</code>属性, <code>onChange()</code>一个挑战。然后,您应该完成<code>handleSubmit</code>方法,以便将组件状态属性<code>submit</code>设置为本地<code>state</code>的当前输入值。 <strong>注意:</strong>您还必须在提交处理程序中调用<code>event.preventDefault()</code> ,以防止将刷新网页的默认表单提交行为。最后,在<code>form</code>之后创建一个<code>h1</code>标记,该<code>form</code>从组件的<code>state</code>呈现<code>submit</code>值。然后您可以键入表单并单击按钮或按Enter键您应该看到您的输入呈现给页面。 </section>
<section id='instructions'>
<code>MyForm</code>组件中是一个带有提交处理程序的空<code>form</code>元素,提交处理程序将在提交表单时被调用。
我们增加了一个提交表单的按钮。你可以看到它的<code>type</code>被设置为<code>submit</code>,表明它是控制表单的按钮。在表单中添加<code>input</code>元素,并像上次挑战一样设置其<code>value</code><code>onChange()</code>属性。然后,你应该完成<code>handleSubmit</code>方法,以便将组件 state 属性<code>submit</code>设置为本地<code>state</code>下的当前输入值。
<strong>注意:</strong>&nbsp; 你还必须在提交处理程序中调用<code>event.preventDefault()</code>,以防止默认的表单提交行为刷新网页。
最后,在<code>form</code>元素之后创建一个<code>h1</code>标签,该标签从组件的<code>state</code>渲染<code>submit</code>的值。然后,你可以在表单中键入任何内容,然后单击按钮(或按 enter 键),你的输入会渲染到页面上。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyForm</code>应该返回一个包含<code>form</code>和<code>h1</code>标的<code>div</code>元素。表单应包含<code>input</code>和<code>button</code>
- text: <code>MyForm</code>应该返回一个包含<code>form</code>和<code>h1</code>标的<code>div</code>元素,其中,表单中应该包括一个<code>input</code>和一个<code>button</code>。
testString: assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyForm)); return (mockedComponent.find('div').children().find('form').length === 1 && mockedComponent.find('div').children().find('h1').length === 1 && mockedComponent.find('form').children().find('input').length === 1 && mockedComponent.find('form').children().find('button').length === 1) })());
- text: <code>MyForm</code>的状态应该使用<code>input</code>和<code>submit</code>属性初始化,两者都设置为空字符串。
- text: <code>MyForm</code>的 state 应该用<code>input</code>和<code>submit</code>属性初始化,两者都为空字符串。
testString: assert(Enzyme.mount(React.createElement(MyForm)).state('input') === '' && Enzyme.mount(React.createElement(MyForm)).state('submit') === '');
- text: 输入<code>input</code>元素应该更新组件状态的<code>input</code>属性。
- text: <code>input</code>元素中的输入应该更新组件中 state 的<code>input</code>属性。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '''' }); return waitForIt(() => mockedComponent.state(''input''))}; const _2 = () => { mockedComponent.find(''input'').simulate(''change'', { target: { value: ''TestInput'' }}); return waitForIt(() => ({ state: mockedComponent.state(''input''), inputVal: mockedComponent.find(''input'').props().value }))}; const before = await _1(); const after = await _2(); assert(before === '''' && after.state === ''TestInput'' && after.inputVal === ''TestInput''); }; '
- text: 提交表单应该运行<code>handleSubmit</code> ,它应该将<code>submit</code>属性设置为等于当前输入的状态
- text: 提交表单应该运行<code>handleSubmit</code>,它应该将 state 中的<code>submit</code>属性设置为当前输入。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '''' }); mockedComponent.setState({submit: ''''}); mockedComponent.find(''input'').simulate(''change'', {target: {value: ''SubmitInput''}}); return waitForIt(() => mockedComponent.state(''submit''))}; const _2 = () => { mockedComponent.find(''form'').simulate(''submit''); return waitForIt(() => mockedComponent.state(''submit''))}; const before = await _1(); const after = await _2(); assert(before === '''' && after === ''SubmitInput''); };'
- text: <code>h1</code>标应该从组件的状态呈现<code>submit</code>字段的值。
- text: <code>h1</code>标应该从组件的 state 渲染<code>submit</code>字段的值。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: '''' }); mockedComponent.setState({submit: ''''}); mockedComponent.find(''input'').simulate(''change'', {target: {value: ''TestInput''}}); return waitForIt(() => mockedComponent.find(''h1'').text())}; const _2 = () => { mockedComponent.find(''form'').simulate(''submit''); return waitForIt(() => mockedComponent.find(''h1'').text())}; const before = await _1(); const after = await _2(); assert(before === '''' && after === ''TestInput''); }; '
```
@ -43,8 +50,8 @@ class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {
input: ",
submit: "
input: '',
submit: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
@ -75,7 +82,6 @@ class MyForm extends React.Component {
);
}
};
```
</div>
@ -85,7 +91,7 @@ class MyForm extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyForm />, document.getElementById('root'))
```
</div>
@ -95,8 +101,43 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
submit: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
handleSubmit(event) {
event.preventDefault()
this.setState({
submit: this.state.input
});
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
value={this.state.input}
onChange={this.handleChange} />
<button type='submit'>Submit!</button>
</form>
<h1>{this.state.submit}</h1>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,26 +3,34 @@ id: 5a24c314108439a4d4036178
title: Create a Controlled Input
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 创建受控输入
forumTopicId: 301385
localeTitle: 创建一个可以控制的输入
---
## Description
<section id="description">您的应用程序可能在<code>state</code>和呈现的UI之间进行更复杂的交互。例如用于文本输入的表单控件元素例如<code>input</code><code>textarea</code>在用户键入时在DOM中维护它们自己的状态。使用React您可以将此可变状态移动到React组件的<code>state</code> 。用户的输入成为应用程序<code>state</code>一部分因此React控制该输入字段的值。通常如果React组件具有用户可以键入的输入字段则它将是受控输入表单。 </section>
<section id='description'>
你的应用程序可能在<code>state</code>和渲染的 UI 之间有更复杂的交互。例如,用于文本输入的表单控件元素(如<code>input</code><code>textarea</code>)在用户键入时在 DOM 中维护自己的 state。通过 React你可以将这种可变 state 转移到 React 组件的<code>state</code>中。用户的输入变成了应用程序<code>state</code>的一部分,因此 React 控制该输入字段的值。通常,如果你的 React 组件具有用户可以键入的输入字段,那么它将是一个受控的输入表单。
</section>
## Instructions
<section id="instructions">代码编辑器具有名为<code>ControlledInput</code>的组件的骨架,以创建受控<code>input</code>元素。组件的<code>state</code>已经使用包含空字符串的<code>input</code>属性进行初始化。此值表示用户在<code>input</code>字段中键入的文本。首先,创建一个名为<code>handleChange()</code>的方法,该方法具有一个名为<code>event</code>的参数。调用该方法时,它会接收一个<code>event</code>对象,该对象包含<code>input</code>元素中的一串文本。您可以使用方法内的<code>event.target.value</code>访问此字符串。使用此新字符串更新组件<code>state</code><code>input</code>属性。在render方法中<code>h4</code>标记上方创建<code>input</code>元素。添加一个<code>value</code>属性,该属性等于组件<code>state</code><code>input</code>属性。然后将<code>onChange()</code>事件处理程序集添加到<code>handleChange()</code>方法。当您在输入框中键入时,该文本由<code>handleChange()</code>方法处理,设置为本地<code>state</code><code>input</code>属性,并在页面的<code>input</code>框中呈现为值。组件<code>state</code>是关于输入数据的单一事实来源。最后但并非最不重要的是,不要忘记在构造函数中添加必要的绑定。 </section>
<section id='instructions'>
代码编辑器具有一个名为<code>ControlledInput</code>的组件框架,用于创建受控的<code>input</code>元素。组件的<code>state</code>已经被包含空字符串的<code>input</code>属性初始化。此值表示用户在<code>input</code>字段中键入的文本。
首先,创建一个名为<code>handleChange()</code>的方法,该方法具有一个名为<code>event</code>的参数。方法被调用时,它接收一个<code>event</code>对象,该对象包含一个来自<code>input</code>元素的字符串文本。你可以使用方法内的<code>event.target.value</code>来访问这个字符串。用这个新字符串更新组件的<code>state</code><code>input</code>属性。
在 render 方法中,在<code>h4</code>标签之上创建<code>input</code>元素。添加一个<code>value</code>属性,它等于组件的<code>state</code><code>input</code>属性。然后将<code>onChange()</code>事件处理程序设置到<code>handleChange()</code>方法。
在输入框中键入时,该文本由<code>handleChange()</code>方法处理,该文本被设置为本地<code>state</code>中的<code>input</code>属性,并渲染在页面上的<code>input</code>框中。组件<code>state</code>是输入数据的唯一真实来源。
最后也是最重要的,不要忘记在构造函数中添加必要的绑定。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>ControlledInput</code>应返回包含<code>input</code>和<code>p</code>标的<code>div</code>元素。
- text: <code>ControlledInput</code>应返回包含一个<code>input</code>标签和<code>p</code>标的<code>div</code>元素。
testString: assert(Enzyme.mount(React.createElement(ControlledInput)).find('div').children().find('input').length === 1 && Enzyme.mount(React.createElement(ControlledInput)).find('div').children().find('p').length === 1);
- text: <code>ControlledInput</code>的状态应该初始化, <code>input</code>属性设置为空字符串
- text: <code>ControlledInput</code>的 state 应该使用设置为空字符串的<code>input</code>属性初始化
testString: assert.strictEqual(Enzyme.mount(React.createElement(ControlledInput)).state('input'), '');
- text: 输入input元素应更新输入的状态和值, <code>p</code>元素应在键入时呈现此状态
- text: input 元素中的键入值应该更新 input 的 state 和值,并且<code>p</code>元素应该在输入时呈现 state
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(ControlledInput)); const _1 = () => { mockedComponent.setState({ input: '''' }); return waitForIt(() => mockedComponent.state(''input''))}; const _2 = () => { mockedComponent.find(''input'').simulate(''change'', { target: { value: ''TestInput'' }}); return waitForIt(() => ({ state: mockedComponent.state(''input''), text: mockedComponent.find(''p'').text(), inputVal: mockedComponent.find(''input'').props().value }))}; const before = await _1(); const after = await _2(); assert(before === '''' && after.state === ''TestInput'' && after.text === ''TestInput'' && after.inputVal === ''TestInput''); }; '
```
@ -39,7 +47,7 @@ class ControlledInput extends React.Component {
constructor(props) {
super(props);
this.state = {
input: "
input: ''
};
// change code below this line
@ -60,7 +68,6 @@ class ControlledInput extends React.Component {
);
}
};
```
</div>
@ -70,7 +77,7 @@ class ControlledInput extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<ControlledInput />, document.getElementById('root'))
```
</div>
@ -80,8 +87,34 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class ControlledInput extends React.Component {
constructor(props) {
super(props);
this.state = {
input: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
render() {
return (
<div>
<input
value={this.state.input}
onChange={this.handleChange} />
<h4>Controlled Input:</h4>
<p>{this.state.input}</p>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,26 +3,47 @@ id: 5a24c314108439a4d4036163
title: Create a React Component
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 创建一个React组件
forumTopicId: 301386
localeTitle: 创建一个 React 组件
---
## Description
<section id="description">定义React组件的另一种方法是使用ES6 <code>class</code>语法。在以下示例中, <code>Kitten</code>扩展了<code>React.Component</code> <blockquote> class Kitten扩展了React.Component { <br>构造函数(道具){ <br>超级(道具); <br> } <br><br> render{ <br>回来( <br> &lt;H1&gt;,您好&lt;/ H1&gt; <br> ; <br> } <br> } </blockquote>这将创建一个扩展<code>React.Component</code>类的ES6类<code>Kitten</code> 。因此, <code>Kitten</code>类现在可以访问许多有用的React功能例如本地状态和生命周期钩子。如果您还不熟悉这些术语请不要担心在以后的挑战中将更详细地介绍它们。另请注意 <code>Kitten</code>类在其中定义了一个调用<code>super()</code><code>constructor</code>函数。它使用<code>super()</code>来调用父类的构造函数,在本例中为<code>React.Component</code> 。构造函数是在使用<code>class</code>关键字创建的对象初始化期间使用的特殊方法。最好用<code>super</code>调用组件的<code>constructor</code> ,并将<code>props</code>传递给它们。这可确保组件正确初始化。现在,请知道包含此代码是标准的。很快你会看到构造函数和<code>props</code>其他用途。 </section>
<section id='description'>
定义 React 组件的另一种方法是使用 ES6 的<code>class</code>语法。在以下示例中,<code>Kitten</code>扩展了<code>React.Component</code>
```jsx
class Kitten extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<h1>Hi</h1>
);
}
}
```
这将创建一个 ES6 类<code>Kitten</code>,它扩展了<code>React.Component</code>类。因此,<code>Kitten</code>类现在可以访问许多有用的 React 功能,例如本地状态和生命周期钩子。如果你还不熟悉这些术语,请不要担心,在以后的挑战中我们将更详细地介绍它们。
另请注意,<code>Kitten</code>类中定义了一个调用<code>super()</code>方法的<code>constructor</code>。它使用<code>super()</code>调用父类的构造函数,即本例中的<code>React.Component</code>。构造函数是使用<code>class</code>关键字创建的特殊方法,它用在实例初始化之前。最佳做法是在组件的<code>constructor</code>里调用<code>super</code>,并将<code>props</code>传递给它们,这样可以保证组件能够正确地初始化。现在,你只需要知道这是标准的做法。很快你会看到构造函数的其他用途以及<code>props</code>
</section>
## Instructions
<section id="instructions"> <code>MyComponent</code>是使用类语法在代码编辑器中定义的。完成编写<code>render</code>方法,以便返回包含带有文本<code>Hello React!</code><code>h1</code><code>div</code>元素<code>Hello React!</code></section>
<section id='instructions'>
<code>MyComponent</code>是使用类语法在代码编辑器中定义的。完成<code>render</code>方法的编写,使其返回<code>div</code>元素,其中包含文本内容为<code>Hello React!</code><code>h1</code>元素。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: React组件应返回<code>div</code>元素。
- text: React 组件应返回一个<code>div</code>元素。
testString: assert(Enzyme.shallow(React.createElement(MyComponent)).type() === 'div');
- text: 返回的<code>div</code>应该在其中呈现一个<code>h1</code>
- text: 返回的<code>div</code>应该渲染一个<code>h1</code>标题
testString: assert(/<div><h1>.*<\/h1><\/div>/.test(Enzyme.shallow(React.createElement(MyComponent)).html()));
- text: <code>h1</code>标应该包含字符串<code>Hello React!</code>
- text: <code>h1</code>标题中应该包含字符串<code>Hello React!</code>。
testString: assert(Enzyme.shallow(React.createElement(MyComponent)).html() === '<div><h1>Hello React!</h1></div>');
```
@ -35,6 +56,7 @@ tests:
<div id='jsx-seed'>
```jsx
class MyComponent extends React.Component {
constructor(props) {
super(props);
@ -47,7 +69,6 @@ class MyComponent extends React.Component {
// change code above this line
}
};
```
</div>
@ -57,7 +78,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -67,8 +88,22 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
// change code below this line
return (
<div>
<h1>Hello React!</h1>
</div>
);
// change code above this line
}
};
```
/section>
</section>

View File

@ -3,15 +3,23 @@ id: 587d7dbc367417b2b2512bb1
title: Create a Simple JSX Element
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 创建一个简单的JSX元素
forumTopicId: 301390
localeTitle: 创建一个简单的 JSX 元素
---
## Description
<section id="description"> <strong>简介:</strong> React是由Facebook创建和维护的开源视图库。它是渲染现代Web应用程序的用户界面UI的绝佳工具。 React使用名为JSX的JavaScript语法扩展允许您直接在JavaScript中编写HTML。这有几个好处。它允许您在HTML中使用JavaScript的完整程序功能并有助于保持代码的可读性。在大多数情况下JSX类似于您已经学过的HTML但是在这些挑战中将会涉及一些关键差异。例如因为JSX是JavaScript的语法扩展所以您实际上可以直接在JSX中编写JavaScript。要做到这一点您只需在花括号中包含您希望被视为<code>{ &#39;this is treated as JavaScript code&#39; }</code> <code>{ &#39;this is treated as JavaScript code&#39; }</code> 。记住这一点因为它用于未来的几个挑战。但是由于JSX不是有效的JavaScript因此必须将JSX代码编译为JavaScript。转换器Babel是这个过程的流行工具。为了您的方便它已经在幕后为这些挑战添加。如果您碰巧编写语法无效的JSX您将看到这些挑战中的第一个测试失败。值得注意的是在引擎盖下挑战是调用<code>ReactDOM.render(JSX, document.getElementById(&#39;root&#39;))</code> 。这个函数调用是将JSX置于React自己的DOM轻量级表示中的原因。然后React使用自己的DOM快照来优化仅更新实际DOM的特定部分。 </section>
<section id='description'>
<strong>简介:</strong>React 是由 Facebook 创建和维护的开源视图库。它是渲染当代 Web 应用程序用户界面UI的绝佳工具。
React 使用名为 JSX 的 JavaScript 语法扩展,允许你直接在 JavaScript 中编写 HTML。这有几个好处。它允许你在 HTML 中使用 JavaScript 的完整程序功能并有助于保持代码的可读性。在大多数情况下JSX 类似于你已经学过的 HTML但是在这些挑战中将会涉及一些关键差异。
例如,因为 JSX 是 JavaScript 的语法扩展,所以你实际上可以直接在 JSX 中编写 JavaScript。要做到这一点你只需在花括号中包含你希望被视为 JavaScript 的代码:<code>{“这被视为 JavaScript 代码”}</code>。请牢记这个写法,你将会在接下来的挑战中使用。
但是,由于浏览器不能解析 JSX因此必须将 JSX 代码编译为 JavaScript。在这个过程中转换器 Babel 是一个很受欢迎的工具。后续挑战已经在后台引入了 Babel你可以直接写 JSX 代码。如果你的代码不符合 JSX 语法,那么挑战中的第一个测试就不会通过。
值得注意的是,这些挑战在底层调用<code>ReactDOM.render(JSX, document.getElementById('root'))</code>。这个函数调用是将你的 JSX 置于 React 自己的轻量级 DOM 中。然后React 使用自己的 DOM 快照来优化更新实际 DOM 的特定部分。
</section>
## Instructions
<section id="instructions"> <strong>说明:</strong>当前代码使用JSX将<code>div</code>元素分配给常量<code>JSX</code> 。用<code>h1</code>元素替换<code>div</code>并添加文本<code>Hello JSX!</code>在里面。 </section>
<section id='instructions'>
<strong>说明:</strong>当前代码使用 JSX 将<code>div</code>元素赋值给常量<code>JSX</code>。将<code>div</code>替换为<code>h1</code>元素,并在其中添加文本<code>Hello JSX!</code>
</section>
## Tests
<section id='tests'>
@ -20,7 +28,7 @@ localeTitle: 创建一个简单的JSX元素
tests:
- text: 常量<code>JSX</code>应该返回一个<code>h1</code>元素。
testString: assert(JSX.type === 'h1');
- text: <code>h1</code>标签应该包含文本<code>Hello JSX!</code>
- text: <code>h1</code>标签应该包含文本<code>Hello JSX!</code>
testString: assert(Enzyme.shallow(JSX).contains('Hello JSX!'));
```
@ -33,6 +41,7 @@ tests:
<div id='jsx-seed'>
```jsx
const JSX = <div></div>;
```
@ -44,7 +53,7 @@ const JSX = <div></div>;
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(JSX, document.getElementById('root'))
```
</div>
@ -54,8 +63,9 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const JSX = <h1>Hello JSX!</h1>;
```
/section>
</section>

View File

@ -3,28 +3,41 @@ id: 5a24c314108439a4d4036170
title: Create a Stateful Component
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 创建一个有状态组件
forumTopicId: 301391
localeTitle: 创建一个有状态组件
---
## Description
<section id="description"> React最重要的主题之一是<code>state</code> 。 State包含应用程序需要了解的任何数据这些数据可能会随时间而变化。您希望应用程序响应状态更改并在必要时显示更新的UI。 React为现代Web应用程序的状态管理提供了一个很好的解决方案。您可以通过在<code>constructor</code>声明组件类的<code>state</code>属性来在React组件中创建状态。这与初始化该组件<code>state</code>被创建时。 <code>state</code>属性必须设置为JavaScript <code>object</code> 。声明它看起来像这样: <blockquote> this.state = { <br> //在这里描述你的州<br>您可以在组件的整个生命周期内访问<code>state</code>对象。您可以更新它在UI中呈现它并将其作为道具传递给子组件。 <code>state</code>对象可以像您需要的那样复杂或简单。请注意,您必须通过扩展<code>React.Component</code>来创建类组件,以便创建这样的<code>state</code></blockquote></section>
<section id='description'>
React中最重要的主题之一是<code>state</code>。 state 包含应用程序需要了解的任何数据,这些数据可能会随时间而变化。你希望应用程序能够响应 state 的变更,并在必要时显示更新后的 UI。React 为现代 Web 应用程序的状态管理提供了一个很好的解决方案。
你可以通过在<code>constructor</code>中的组件类上声明<code>state</code>属性来在 React 组件中创建 state它在创建时使用<code>state</code>初始化组件。<code>state</code>属性必须设置为 JavaScript<code>对象</code>。声明如下:
```jsx
this.state = {
// describe your state here
}
```
你可以在组件的整个生命周期内访问<code>state</code>对象,你可以更新它、在 UI 中渲染它,也可以将其作为 props 传递给子组件。<code>state</code>对象的使用可以很简单,亦可以很复杂,就看你怎么用了。请注意,你必须通过扩展<code>React.Component</code>来创建类组件,以便像这样创建<code>state</code>
</section>
## Instructions
<section id="instructions">代码编辑器中有一个组件试图从其<code>state</code>呈现<code>name</code>属性。但是,没有定义<code>state</code> 。初始化与组件<code>state</code><code>constructor</code> ,并指定你的名字的属性<code>name</code></section>
<section id='instructions'>
代码编辑器中有一个组件试图从其<code>state</code>中渲染一个<code>name</code>属性,但是<code>state</code>还没有定义。在<code>constructor</code>中使用<code>state</code>初始化组件,并将你的名字赋给<code>name</code>属性。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>StatefulComponent</code>应该存在并呈现
- text: <code>StatefulComponent</code>应该存在并被渲染
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(StatefulComponent)); return mockedComponent.find('StatefulComponent').length === 1; })());
- text: <code>StatefulComponent</code>应该呈现<code>div</code><code>h1</code>元素。
- text: <code>StatefulComponent</code>应该渲染一个<code>div</code>元素和一个<code>h1</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(StatefulComponent)); return mockedComponent.find('div').length === 1 && mockedComponent.find('h1').length === 1; })());
- text: 应使用设置为字符串的属性<code>name</code>初始化<code>StatefulComponent</code>
- text: 应使用设置为字符串的<code>name</code>属性来初始化<code>StatefulComponent</code>的 state
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(StatefulComponent)); const initialState = mockedComponent.state(); return ( typeof initialState === 'object' && typeof initialState.name === 'string'); })());
- text: <code>StatefulComponent</code>的属性<code>name</code>在<code>h1</code>元素中呈现
- text: <code>StatefulComponent</code>中 state 的<code>name</code>属性应该渲染在<code>h1</code>元素
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(StatefulComponent)); const initialState = mockedComponent.state(); return mockedComponent.find('h1').text() === initialState.name; })());
```
@ -37,6 +50,7 @@ tests:
<div id='jsx-seed'>
```jsx
class StatefulComponent extends React.Component {
constructor(props) {
super(props);
@ -51,7 +65,6 @@ class StatefulComponent extends React.Component {
);
}
};
```
</div>
@ -61,7 +74,7 @@ class StatefulComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<StatefulComponent />, document.getElementById('root'))
```
</div>
@ -71,8 +84,23 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class StatefulComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'freeCodeCamp!'
}
}
render() {
return (
<div>
<h1>{this.state.name}</h1>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,26 +3,44 @@ id: 5a24c314108439a4d4036162
title: Create a Stateless Functional Component
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 创建无状态功能组件
forumTopicId: 301392
localeTitle: 创建一个无状态的函数组件
---
## Description
<section id="description">组件是React的核心。 React中的所有内容都是一个组件在这里您将学习如何创建一个组件。有两种方法可以创建React组件。第一种方法是使用JavaScript函数。以这种方式定义组件会创建<em>无状态功能组件</em> 。应用程序中的状态概念将在以后的挑战中介绍。现在,将无状态组件视为可以接收数据并对其进行渲染的组件,但不管理或跟踪对该数据的更改。 我们将介绍在下一个挑战中创建React组件的第二种方法。要创建一个带有函数的组件您只需编写一个返回JSX或<code>null</code>的JavaScript函数。需要注意的一件重要事情是React要求您的函数名称以大写字母开头。这是一个在JSX中分配HTML类的无状态功能组件的示例 <blockquote> //被转换后,&lt;div&gt;将有一个CSS类&#39;customClass&#39; <br> const DemoComponent = function{ <br>回来( <br> &lt;div className =&#39;customClass&#39;/&gt; <br> ; <br> }; </blockquote>因为JSX组件代表HTML所以您可以将几个组件放在一起以创建更复杂的HTML页面。这是React提供的组件架构的关键优势之一。它允许您从许多独立的独立的组件中组合UI。这使得构建和维护复杂的用户界面变得更加容易。 </section>
<section id='description'>
组件是 React 的核心。React 中的所有内容都是一个组件,在这里你将学习如何创建一个组件。
有两种方法可以创建 React 组件。第一种方法是使用 JavaScript 函数。以这种方式定义组件会创建<em>无状态功能组件</em>。应用程序中的状态概念将在以后的挑战中介绍。目前,可以将无状态组件视为可以接收数据并对其进行渲染的组件,但是它不管理或跟踪对数据的更改,我们将在下一次挑战中介绍创建 React 组件的第二种方法。
要用函数创建组件,只需编写一个返回 JSX 或<code>null</code>的 JavaScript 函数。需要注意的一点是React 要求你的函数名以大写字母开头。下面是一个无状态功能组件的示例,该组件在 JSX 中分配一个 HTML 的 class
```jsx
// After being transpiled, the <div> will have a CSS class of 'customClass'
const DemoComponent = function() {
return (
<div className='customClass' />
);
};
```
因为 JSX 组件代表 HTML所以你可以将几个组件放在一起以创建更复杂的 HTML 页面,这是 React 提供的组件架构的关键优势之一,它允许你用许多独立的组件组成 UI。这使得构建和维护复杂的用户界面变得更加容易。
</section>
## Instructions
<section id="instructions">代码编辑器有一个名为<code>MyComponent</code>的函数。完成此函数,以便返回包含一些文本字符串的单个<code>div</code>元素。 <strong>注意:</strong>该文本被视为<code>div</code>元素的子元素,因此您将无法使用自闭合标记。 </section>
<section id='instructions'>
代码编辑器中有一个名为<code>MyComponent</code>的函数。完成此函数,使其返回包含一些文本字符串的单个<code>div</code>元素。
<strong>注意:</strong>&nbsp;文本被视为是<code>div</code>的子元素,因此你将不能使用自闭合标签。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyComponent</code>应该返回JSX。
- text: <code>MyComponent</code>应该返回 JSX。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.length === 1; })());
- text: <code>MyComponent</code>应该返回一个<code>div</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.children().type() === 'div' })());
- text: <code>div</code>元素应包含一文本。
- text: <code>div</code>元素应包含一文本字符串
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find('div').text() !== ''; })());
```
@ -42,7 +60,6 @@ const MyComponent = function() {
// change code above this line
}
```
</div>
@ -52,7 +69,7 @@ const MyComponent = function() {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -62,8 +79,17 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const MyComponent = function() {
// change code below this line
return (
<div>
Demo Solution
</div>
);
// change code above this line
}
```
/section>
</section>

View File

@ -3,15 +3,22 @@ id: 5a24c314108439a4d4036160
title: Define an HTML Class in JSX
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 在JSX中定义HTML
forumTopicId: 301393
localeTitle: 在 JSX 中定义一个 HTML Class
---
## Description
<section id="description">现在您已经开始编写JSX了您可能想知道它与HTML的区别。到目前为止似乎HTML和JSX完全相同。 JSX的一个关键区别是你不能再使用单词<code>class</code>来定义HTML类。这是因为<code>class</code>是JavaScript中的保留字。相反JSX使用<code>className</code> 。事实上JSX中所有HTML属性和事件引用的命名约定都变成了camelCase。例如JSX中的单击事件是<code>onClick</code> ,而不是<code>onclick</code> 。同样, <code>onchange</code>变为<code>onChange</code> 。虽然这是一个微妙的差异,但重要的是要记住前进。 </section>
<section id='description'>
现在你已经习惯了编写 JSX你可能想知道它与 HTML 有什么不同。
到目前为止HTML 和 JSX 似乎完全相同。
JSX 的一个关键区别是你不能再使用<code>class</code>这个单词来定义 HTML 的 class 名。这是因为<code>class</code>是 JavaScript 中的关键字。JSX 使用<code>className</code>代替。
事实上JSX 中所有 HTML 属性和事件引用的命名约定都变成了驼峰式。例如JSX 中的单击事件是 <code>onClick</code>,而不是 <code>onclick</code>。同样,<code>onchange</code>变成了<code>onChange</code>。虽然这是一个微妙的差异,但请你一定要记住。
</section>
## Instructions
<section id="instructions">将一个<code>myDiv</code><code>myDiv</code> JSX代码中提供的<code>div</code></section>
<section id='instructions'>
将 class<code>myDiv</code> 应用于 JSX 提供的<code>div</code>上。
</section>
## Tests
<section id='tests'>
@ -20,7 +27,7 @@ localeTitle: 在JSX中定义HTML类
tests:
- text: 常量<code>JSX</code>应该返回一个<code>div</code>元素。
testString: assert.strictEqual(JSX.type, 'div');
- text: <code>div</code>有一<code>myDiv</code>
- text: <code>div</code>有一<code>myDiv</code>class
testString: assert.strictEqual(JSX.props.className, 'myDiv');
```
@ -38,7 +45,6 @@ const JSX = (
<h1>Add a class to this div</h1>
</div>
);
```
</div>
@ -48,7 +54,7 @@ const JSX = (
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(JSX, document.getElementById('root'))
```
</div>
@ -58,8 +64,12 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const JSX = (
<div className = 'myDiv'>
<h1>Add a class to this div</h1>
</div>);
```
/section>
</section>

View File

@ -3,31 +3,38 @@ id: 5a24c314108439a4d403618b
title: Give Sibling Elements a Unique Key Attribute
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 为兄弟元素提供唯一的键属性
forumTopicId: 301394
localeTitle: 给同级元素一个唯一的键属性
---
## Description
<section id="description">最后一项挑战展示了如何使用<code>map</code>方法根据用户输入动态呈现多个元素。但是,这个例子中缺少一个重要的部分。创建元素数组时,每个元素都需要将<code>key</code>属性设置为唯一值。 React使用这些键来跟踪添加更改或删除的项目。当以任何方式修改列表时这有助于使重新呈现过程更有效。请注意键只需要在兄弟元素之间是唯一的它们在您的应用程序中不需要是全局唯一的。 </section>
<section id='description'>
上一个挑战展示了如何使用<code>map</code>方法根据用户输入动态渲染多个元素。然而,这个例子中缺少一个重要的部分。创建元素数组时,每个元素都需要一个设置为唯一值的<code>key</code>属性。React 使用这些键来跟踪哪些项目被添加、更改或删除。这有助于在以任何方式修改列表时提高重新渲染过程的效率。请注意,键只需要在同级元素之间是唯一的,它们不需要在应用程序中是全局唯一的。
</section>
## Instructions
<section id="instructions">代码编辑器有一个包含一些前端框架的数组和一个名为<code>Frameworks()</code>的无状态功能组件。 <code>Frameworks()</code>需要将数组映射到无序列表,就像上一次挑战一样。完成编写<code>map</code>回调以返回<code>frontEndFrameworks</code>数组中每个框架的<code>li</code>元素。这一次,请确保为每个<code>li</code>一个<code>key</code>属性,设置为唯一值。通常,您希望使键成为唯一标识要呈现的元素的键。作为最后的手段,可以使用数组索引,但通常您应该尝试使用唯一标识。 </section>
<section id='instructions'>
代码编辑器有一个数组,它包含一些前端框架和一个名为<code>Frameworks()</code>的无状态函数组件。<code>Frameworks()</code>需要将数组映射到无序列表,就像上一个挑战一样。完成<code>map</code>回调,为<code>frontEndFrameworks</code>数组中的每个框架返回一个<code>li</code>元素。这次,确保给每个<code>li</code><code>key</code>属性设置一个唯一的值。
通常,你希望使 key 能唯一标识要渲染的元素。作为最后的手段,可以使用数组索引,但通常你应该尝试使用唯一标识。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>Frameworks</code>组件应该存在并呈现给页面。
testString: 'assert(Enzyme.mount(React.createElement(Frameworks)).find("Frameworks").length === 1, "The <code>Frameworks</code> component should exist and render to the page.");'
- text: <code>Frameworks</code>应该呈现<code>h1</code>元素。
testString: 'assert(Enzyme.mount(React.createElement(Frameworks)).find("h1").length === 1, "<code>Frameworks</code> should render an <code>h1</code> element.");'
- text: <code>Frameworks</code>应该呈现<code>ul</code>元素。
testString: 'assert(Enzyme.mount(React.createElement(Frameworks)).find("ul").length === 1, "<code>Frameworks</code> should render a <code>ul</code> element.");'
- text: <code>ul</code>标记应呈现6个子<code>li</code>元素。
testString: 'assert(Enzyme.mount(React.createElement(Frameworks)).find("ul").children().length === 6 && Enzyme.mount(React.createElement(Frameworks)).find("ul").childAt(0).name() === "li" && Enzyme.mount(React.createElement(Frameworks)).find("li").length === 6, "The <code>ul</code> tag should render 6 child <code>li</code> elements.");'
- text: 每个列表项元素都应具有唯一的<code>key</code>属性。
testString: 'assert((() => { const ul = Enzyme.mount(React.createElement(Frameworks)).find("ul"); const keys = new Set([ ul.childAt(0).key(), ul.childAt(1).key(), ul.childAt(2).key(), ul.childAt(3).key(), ul.childAt(4).key(), ul.childAt(5).key(), ]); return keys.size === 6; })(), "Each list item element should have a unique <code>key</code> attribute.");'
- text: <code>Frameworks</code> 组件应该存在并渲染到页面。
testString: assert(Enzyme.mount(React.createElement(Frameworks)).find('Frameworks').length === 1);
- text: <code>Frameworks</code>应该渲染一个<code>h1</code>元素。
testString: assert(Enzyme.mount(React.createElement(Frameworks)).find('h1').length === 1);
- text: <code>Frameworks</code>应该渲染一个<code>ul</code>元素。
testString: assert(Enzyme.mount(React.createElement(Frameworks)).find('ul').length === 1);
- text: <code>ul</code>标签应该渲染 6 个<code>li</code>元素。
testString: assert(Enzyme.mount(React.createElement(Frameworks)).find('ul').children().length === 6 && Enzyme.mount(React.createElement(Frameworks)).find('ul').childAt(0).name() === 'li' && Enzyme.mount(React.createElement(Frameworks)).find('li').length === 6);
- text: 每个列表项元素都应该有一个唯一的<code>key</code>属性。
testString: assert((() => { const ul = Enzyme.mount(React.createElement(Frameworks)).find('ul'); const keys = new Set([ ul.childAt(0).key(), ul.childAt(1).key(), ul.childAt(2).key(), ul.childAt(3).key(), ul.childAt(4).key(), ul.childAt(5).key(), ]); return keys.size === 6; })());
- text: 每个列表元素都应该包含 <code>frontEndFrameworks</code> 里的文本。
testString: assert((() => {const li = Enzyme.mount(React.createElement(Frameworks)).find('ul').children(); return [...Array(5)].every((_, i) => frontEndFrameworks.includes(li.at(i).text()))})());
```
@ -39,6 +46,7 @@ tests:
<div id='jsx-seed'>
```jsx
const frontEndFrameworks = [
'React',
'Angular',
@ -59,7 +67,6 @@ function Frameworks() {
</div>
);
};
```
</div>
@ -69,7 +76,7 @@ function Frameworks() {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<Frameworks />, document.getElementById('root'))
```
</div>
@ -79,8 +86,28 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const frontEndFrameworks = [
'React',
'Angular',
'Ember',
'Knockout',
'Backbone',
'Vue'
];
function Frameworks() {
const renderFrameworks = frontEndFrameworks.map((fw, i) => <li key={i}>{fw}</li>);
return (
<div>
<h1>Popular Front End JavaScript Frameworks</h1>
<ul>
{renderFrameworks}
</ul>
</div>
);
};
```
/section>
</section>

View File

@ -3,24 +3,35 @@ id: 5a24c314108439a4d4036181
title: Introducing Inline Styles
challengeType: 6
isRequired: false
videoUrl: ''
forumTopicId: 301395
localeTitle: 介绍内联样式
---
## Description
<section id="description">还有其他复杂的概念可以为您的React代码添加强大的功能。但是你可能想知道如何设置你在React中创建的那些JSX元素的更简单的问题。您可能知道它与使用HTML完全不同因为<a target="_blank" href="/learn/front-end-libraries/react/define-an-html-class-in-jsx">您将类应用于JSX元素的方式</a> 。如果从样式表导入样式,它就没有太大的不同。使用<code>className</code>属性将类应用于JSX元素并将样式应用于样式表中的类。另一种选择是应用<strong><em>内联</em></strong>样式这在ReactJS开发中非常常见。您将内联样式应用于JSX元素类似于您在HTML中的操作方式但有一些JSX差异。以下是HTML中内联样式的示例 <code>&lt;div style=&quot;color: yellow; font-size: 16px&quot;&gt;Mellow Yellow&lt;/div&gt;</code> JSX元素使用<code>style</code>属性但由于JSX的转换方式您可以不要将值设置为<code>string</code> 。相反您将其设置为等于JavaScript <code>object</code> 。这是一个例子: <code>&lt;div style={{color: &quot;yellow&quot;, fontSize: 16}}&gt;Mellow Yellow&lt;/div&gt;</code>注意我们如何使用“fontSize”属性这是因为React不接受样式对象中的kebab-case键。 React将在HTML中为我们应用正确的属性名称。 </section>
<section id='description'>
还有其他复杂的概念可以为你的 React 代码增加强大的功能。但是,你可能会想知道更简单的问题,比如:如何对在 React 中创建的 JSX 元素进行风格化。你可能知道,由于<a target="_blank" href="define-an-html-class-in-jsx">将 class 应用于 JSX 元素的方式</a>与 HTML 中的使用并不完全相同。
如果从样式表导入样式,它就没有太大的不同。使用<code>className</code>属性将 class 应用于 JSX 元素,并将样式应用于样式表中的 class。另一种选择是使用<strong><em>内联</em></strong>样式,这在 ReactJS 开发中非常常见。
你将内联样式应用于 JSX 元素,类似于你在 HTML 中的操作方式,但有一些 JSX 差异。以下是 HTML 中内联样式的示例:
<code>&lt;div style="color: yellow; font-size: 16px"&gt;Mellow Yellow&lt;/div&gt;</code>
JSX 元素使用<code>style</code>属性,但是由于 JSX 的传输方式,你不能将值设置为<code>字符串</code>。相反,你应将其设置为 JavaScript<code>对象</code>。这里有一个例子:
<code>&lt;div style={{color: "yellow", fontSize: 16}}&gt;Mellow Yellow&lt;/div&gt;</code>
注意我们使用驼峰式命名的 "fontSize" 属性,这是因为 React 不会接受样式对象中的连字符。React 将在 HTML 中为我们应用正确的属性名称。
</section>
## Instructions
<section id="instructions">在代码编辑器中为<code>div</code>添加<code>style</code>属性为文本提供红色和字体大小为72px的颜色。请注意您可以选择将字体大小设置为数字省略单位“px”或将其写为“72px”。 </section>
<section id='instructions'>
在代码编辑器的<code>div</code>中添加一个<code>style</code>属性,使文本颜色为红色,字体大小为 72px。
请注意,你可以选择将字体大小设置为数字,省略单位 "px",或者将其写为 "72px"。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: 组件应呈现<code>div</code>元素。
- text: 组件应该渲染一个<code>div</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Colorful)); return mockedComponent.children().type() === 'div'; })());
- text: <code>div</code>元素应该是<code>red</code>
- text: <code>div</code>元素应该是<code>红色</code>
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Colorful)); return mockedComponent.children().props().style.color === 'red'; })());
- text: <code>div</code>元素的字体大小应为<code>72px</code>。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Colorful)); return (mockedComponent.children().props().style.fontSize === 72 || mockedComponent.children().props().style.fontSize === '72' || mockedComponent.children().props().style.fontSize === '72px'); })());
@ -35,6 +46,7 @@ tests:
<div id='jsx-seed'>
```jsx
class Colorful extends React.Component {
render() {
return (
@ -52,7 +64,7 @@ class Colorful extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<Colorful />, document.getElementById('root'))
```
</div>
@ -62,8 +74,16 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class Colorful extends React.Component {
render() {
return (
<div style={{color: "red", fontSize: 72}}>Big Red</div>
);
}
};
```
/section>
</section>

View File

@ -3,15 +3,23 @@ id: 5a24c314108439a4d4036161
title: Learn About Self-Closing JSX Tags
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 了解自我关闭JSX标签
forumTopicId: 301396
localeTitle: 了解自动闭合的 JSX 标记
---
## Description
<section id="description">到目前为止您已经看到JSX与HTML的不同之处在于使用<code>className</code><code>class</code>来定义HTML类。 JSX与HTML的另一个重要方式是自闭标签。在HTML中几乎所有标签都有开始和结束标签 <code>&lt;div&gt;&lt;/div&gt;</code> ;结束标记在您要关闭的标记名称之前始终具有正斜杠。但是HTML中有一些称为“自闭标签”的特殊实例或者在另一个标签可以启动之前不需要开始和结束标签的标签。例如换行标记可以写成<code>&lt;br&gt;</code><code>&lt;br /&gt;</code> ,但不应该写为<code>&lt;br&gt;&lt;/br&gt;</code> 因为它不包含任何内容。在JSX中规则略有不同。任何JSX元素都可以使用自闭合标记编写并且必须关闭每个元素。例如换行标记必须始终写为<code>&lt;br /&gt;</code>才能成为可以转换的有效JSX。另一方面 <code>&lt;div&gt;</code>可以写为<code>&lt;div /&gt;</code><code>&lt;div&gt;&lt;/div&gt;</code> 。不同之处在于,在第一个语法版本中,无法在<code>&lt;div /&gt;</code>包含任何内容。您将在以后的挑战中看到在呈现React组件时此语法非常有用。 </section>
<section id='description'>
到目前为止,你已经看到 JSX 与 HTML 的不同之处在于使用<code>className</code>和使用<code>class</code>来定义 HTML 的 class。
JSX 不同于 HTML 的另一个重要方面是自闭合标签。
在HTML中几乎所有的标签都有一个开始和结束标签<code>&lt;div&gt;&lt;/div&gt;</code>结束标签在你要关闭的标签名之前始终具有正斜杠。但是HTML 中有一些称为“自闭合标签”的特殊实例,它们在另一个标签开始之前,不需要开始和结束标签都存在。
例如,换行标签可以写成<code>&lt;br&gt;</code>或者<code>&lt;br /&gt;</code>,但是不应该写成<code>&lt;br&gt;&lt;/br&gt;</code>,因为它不包含任何内容。
在 JSX 中,规则略有不同。任何 JSX 元素都可以使用自闭合标签编写,并且每个元素都必须关闭。例如,换行标签必须始终编写为<code>&lt;br /&gt;</code>。另一方面<code>&lt;div&gt;</code>可以写成<code>&lt;div /&gt;</code>或者<code>&lt;div&gt;&lt;/div&gt;</code>。不同之处在于,在第一个语法版本中,无法在<code>&lt;div /&gt;</code>中包含任何内容。在后面的挑战中你会发现,这种语法在渲染 React 组件时非常有用。
</section>
## Instructions
<section id="instructions">修复代码编辑器中的错误使其成为有效的JSX并成功转换。确保您不更改任何内容 - 您只需要在需要的地方关闭标签。 </section>
<section id='instructions'>
修复代码编辑器中的错误,使其成为有效的 JSX 并成功转换。确保你不更改任何内容--你只需要在需要的地方关闭标签。
</section>
## Tests
<section id='tests'>
@ -22,7 +30,7 @@ tests:
testString: assert.strictEqual(JSX.type, 'div');
- text: <code>div</code>应该包含一个<code>br</code>标签。
testString: assert(Enzyme.shallow(JSX).find('br').length === 1);
- text: <code>div</code>应包含<code>hr</code>标
- text: <code>div</code>应包含一个<code>hr</code>标
testString: assert(Enzyme.shallow(JSX).find('hr').length === 1);
```
@ -54,7 +62,7 @@ const JSX = (
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(JSX, document.getElementById('root'))
```
</div>
@ -64,8 +72,17 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const JSX = (
<div>
{/* change code below this line */}
<h2>Welcome to React!</h2> <br />
<p>Be sure to close all tags!</p>
<hr />
{/* change code above this line */}
</div>
);
```
/section>
</section>

View File

@ -3,28 +3,33 @@ id: 5a24c314108439a4d4036180
title: Optimize Re-Renders with shouldComponentUpdate
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用shouldComponentUpdate优化重新渲染
forumTopicId: 301398
localeTitle: 使用 shouldComponentUpdate 优化重新渲染
---
## Description
<section id="description">到目前为止,如果任何组件接收到新的<code>state</code>或新的<code>props</code> 它会重新呈现自己及其所有子项。这通常没问题。但是React提供了一个生命周期方法您可以在子组件接收新<code>state</code><code>props</code>时调用它,并特别声明组件是否应该更新。方法是<code>shouldComponentUpdate()</code> ,它将<code>nextProps</code><code>nextState</code>作为参数。此方法是优化性能的有用方法。例如,默认行为是您的组件在收到新<code>props</code>时重新渲染,即使<code>props</code>未更改。您可以使用<code>shouldComponentUpdate()</code>通过比较<code>props</code>来防止这种情况。该方法必须返回一个<code>boolean</code>告诉React是否更新组件。您可以将当前道具 <code>this.props</code> )与下一个道具( <code>nextProps</code> )进行比较,以确定是否需要更新,并相应地返回<code>true</code><code>false</code></section>
<section id='description'>
到目前为止,如果任何组件接收到新的<code>state</code>或新的<code>props</code>,它会重新渲染自己及其所有子组件。这通常是好的。但是 React 提供了一种生命周期方法,当子组件接收到新的<code>state</code><code>props</code>时,你可以调用该方法,并特别声明组件是否应该更新。方法是<code>shouldComponentUpdate()</code>,它将<code>nextProps</code><code>nextState</code>作为参数。
这种方法是优化性能的有效方法。例如,默认行为是,当组件接收到新的<code>props</code>时,即使<code>props</code>没有改变,它也会重新渲染。你可以通过使用<code>shouldComponentUpdate()</code>比较<code>props</code>来防止这种情况。该方法必须返回一个布尔值,该值告诉 React 是否更新组件。你可以比较当前的 props<code>this.props</code>)和下一个 props<code>nextProps</code>),以确定你是否需要更新,并相应地返回<code>true</code><code>false</code>
</section>
## Instructions
<section id="instructions"> <code>shouldComponentUpdate()</code>方法添加到名为<code>OnlyEvens</code>的组件中。目前,此方法返回<code>true</code>因此每次收到新<code>props</code>时, <code>OnlyEvens</code>重新渲染。修改方法,以便<code>OnlyEvens</code>更新仅当<code>value</code>的新道具的是偶数。单击“ <code>Add</code>按钮,在触发其他生命周期挂钩时,在浏览器控制台中查看事件的顺序。 </section>
<section id='instructions'>
<code>shouldComponentUpdate()</code>方法添加到名为<code>OnlyEvens</code>的组件中。目前,该方法返回<code>true</code>,因此每次收到新的<code>props</code>时,<code>OnlyEvens</code>都会重新渲染。修改该方法,以便<code>OnlyEvens</code>仅在其新 props 的<code>value</code>为偶数时更新。单击<code>Add</code>按钮,在触发其他生命周期钩子时,在浏览器控制台中查看事件的顺序。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>Controller</code>组件应将<code>OnlyEvens</code>组件呈现为<code>OnlyEvens</code>组件。
- text: <code>Controller</code>组件应将<code>OnlyEvens</code>组件渲染为子组件。
testString: assert((() => { const mockedComponent = Enzyme.mount(React.createElement(Controller)); return mockedComponent.find('Controller').length === 1 && mockedComponent.find('OnlyEvens').length === 1; })());
- text: 应该在<code>OnlyEvens</code>组件上定义<code>shouldComponentUpdate</code>方法。
testString: assert((() => { const child = React.createElement(OnlyEvens).type.prototype.shouldComponentUpdate.toString().replace(/s/g,''); return child !== 'undefined'; })());
- text: <code>OnlyEvens</code>组件应返回一个<code>h1</code>标,该标记呈现<code>this.props.value</code>的值。
- text: <code>OnlyEvens</code>组件应返回一个<code>h1</code>标,该标签渲染<code>this.props.value</code>的值。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(Controller)); const first = () => { mockedComponent.setState({ value: 1000 }); return waitForIt(() => mockedComponent.find(''h1'').html()); }; const second = () => { mockedComponent.setState({ value: 10 }); return waitForIt(() => mockedComponent.find(''h1'').html()); }; const firstValue = await first(); const secondValue = await second(); assert(firstValue === ''<h1>1000</h1>'' && secondValue === ''<h1>10</h1>''); }; '
- text: <code>OnlyEvens</code>只有在<code>nextProps.value</code>为偶数<code>OnlyEvens</code>应该重新渲染。
- text: 只有在<code>nextProps.value</code>为偶数时,<code>OnlyEvens</code>才会重新渲染。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(Controller)); const first = () => { mockedComponent.setState({ value: 8 }); return waitForIt(() => mockedComponent.find(''h1'').text()); }; const second = () => { mockedComponent.setState({ value: 7 }); return waitForIt(() => mockedComponent.find(''h1'').text()); }; const third = () => { mockedComponent.setState({ value: 42 }); return waitForIt(() => mockedComponent.find(''h1'').text()); }; const firstValue = await first(); const secondValue = await second(); const thirdValue = await third(); assert(firstValue === ''8'' && secondValue === ''8'' && thirdValue === ''42''); }; '
```
@ -47,9 +52,6 @@ class OnlyEvens extends React.Component {
return true;
// change code above this line
}
componentWillReceiveProps(nextProps) {
console.log('Receiving new props...');
}
componentDidUpdate() {
console.log('Component re-rendered.');
}
@ -80,7 +82,6 @@ class Controller extends React.Component {
);
}
};
```
</div>
@ -90,7 +91,7 @@ class Controller extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<Controller />, document.getElementById('root'))
```
</div>
@ -100,8 +101,48 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class OnlyEvens extends React.Component {
constructor(props) {
super(props);
}
shouldComponentUpdate(nextProps, nextState) {
console.log('Should I update?');
// change code below this line
return nextProps.value % 2 === 0;
// change code above this line
}
componentDidUpdate() {
console.log('Component re-rendered.');
}
render() {
return <h1>{this.props.value}</h1>
}
};
class Controller extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 0
};
this.addValue = this.addValue.bind(this);
}
addValue() {
this.setState({
value: this.state.value + 1
});
}
render() {
return (
<div>
<button onClick={this.addValue}>Add</button>
<OnlyEvens value={this.state.value}/>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,26 +3,31 @@ id: 5a24c314108439a4d403616c
title: Override Default Props
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 覆盖默认道具
forumTopicId: 301399
localeTitle: 覆盖默认的 Props
---
## Description
<section id="description">设置默认道具的能力是React中的一个有用功能。覆盖默认道具的方法是显式设置组件的prop值。 </section>
<section id='description'>
在 React 中,设置默认的 props 是一个很有用的特性,显式设置组件的 prop 值即可覆盖默认 props。
</section>
## Instructions
<section id="instructions"> <code>ShoppingCart</code>组件现在呈现子组件<code>Items</code> 。此<code>Items</code>组件的默认prop <code>quantity</code>设置为整数<code>0</code> 。通过为<code>quantity</code>传递值<code>10</code>来覆盖默认支柱。 <strong>注意:</strong>请记住向组件添加prop的语法与添加HTML属性的方式类似。但是由于<code>quantity</code>的值是一个整数,因此它不会引用引号,但应该用大括号括起来。例如, <code>{100}</code> 。此语法告诉JSX将大括号内的值直接解释为JavaScript。 </section>
<section id='instructions'>
<code>ShoppingCart</code>组件现在渲染了一个子组件<code>Items</code>。该<code>Items</code>组件有一个默认<code>quantity</code>prop其值被设置为整数<code>0</code>。通过传入数值<code>10</code>来覆盖<code>quantity</code>的默认 prop。
<strong>注意:</strong>&nbsp;请记住,向组件添加 prop 的语法与添加 HTML 属性类似。但是,由于<code>quantity</code>的值是整数,所以它不会加引号,但应该用花括号括起来,例如<code>{100}</code>。这个语法告诉 JSX 直接将花括号中的值解释为 JavaScript。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>ShoppingCart</code>应该呈现组件。
- text: 应该渲染<code>ShoppingCart</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart)); return mockedComponent.find('ShoppingCart').length === 1; })());
- text: 该组件<code>Items</code>应该呈现
- text: 应该渲染<code>Items</code>组件
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart)); return mockedComponent.find('Items').length === 1; })());
- text: '<code>Items</code>组件应具有从<code>ShoppingCart</code>组件传递的<code>{ quantity: 10 }</code>的prop。'
- text: '<code>Items</code>组件应该有一个<code>{ quantity: 10 }</code>的prop,该 prop 是从<code>ShoppingCart</code>组件传递过去的。'
testString: "getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart)); return mockedComponent.find('Items').props().quantity == 10 && getUserInput('index').replace(/ /g,'').includes('<Itemsquantity={10}/>'); })());"
```
@ -53,7 +58,6 @@ class ShoppingCart extends React.Component {
{ /* change code above this line */ }
}
};
```
</div>
@ -63,7 +67,7 @@ class ShoppingCart extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<ShoppingCart />, document.getElementById('root'))
```
</div>
@ -73,8 +77,26 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const Items = (props) => {
return <h1>Current Quantity of Items in Cart: {props.quantity}</h1>
}
Items.defaultProps = {
quantity: 0
}
class ShoppingCart extends React.Component {
constructor(props) {
super(props);
}
render() {
{ /* change code below this line */ }
return <Items quantity = {10} />
{ /* change code above this line */ }
}
};
```
/section>
</section>

View File

@ -3,30 +3,35 @@ id: 5a24c314108439a4d403617b
title: Pass a Callback as Props
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 回调作为道具传递
forumTopicId: 301400
localeTitle: 传递回调作为 Props
---
## Description
<section id="description">您可以将<code>state</code>作为道具传递给子组件但您不仅限于传递数据。您还可以将处理函数或在React组件上定义的任何方法传递给子组件。这是允许子组件与其父组件交互的方式。您可以将方法传递给孩子就像常规道具一样。它被分配了一个名称您可以在子组件中的<code>this.props</code>下访问该方法名称。 </section>
<section id='description'>
你可以将<code>state</code>作为 props 传递给子组件,但不仅限于传递数据。你也可以将处理函数或在 React 组件中定义的任何方法传递给子组件。这就是允许子组件与父组件交互的方式。你可以把方法像普通 prop 一样传递给子组件,它会被分配一个名字,你可以在子组件中的<code>this.props</code>下访问该方法的名字。
</section>
## Instructions
<section id="instructions">代码编辑器中列出了三个组件。 <code>MyApp</code>组件是将呈现<code>GetInput</code><code>RenderInput</code>子组件的父组件。将<code>GetInput</code>组件添加到<code>MyApp</code>的render方法然后从<code>MyApp</code><code>state</code>向它传递一个名为<code>input</code>的prop<code>input</code>分配给<code>inputValue</code> 。还要创建一个名为<code>handleChange</code>的prop并将输入处理程序<code>handleChange</code>给它。接下来,将<code>RenderInput</code>添加到<code>MyApp</code>的render方法然后创建一个名为<code>input</code>的prop并将<code>inputValue</code><code>state</code>传递给它。完成后,您将能够在<code>GetInput</code>组件中<code>input</code>字段然后通过props调用其父级中的处理程序方法。这将更新父级<code>state</code>的输入该输入作为props传递给两个子级。观察数据如何在组件之间流动以及单个事实源如何保持父组件的<code>state</code> 。不可否认这个例子有点人为但应该用来说明如何在React组件之间传递数据和回调。 </section>
<section id='instructions'>
代码编辑器中列出了三个组件。<code>MyApp</code>是父组件,<code>GetInput</code><code>RenderInput</code>是它的子组件。将<code>GetInput</code>组件添加到<code>MyApp</code>的 render 方法,然后将<code>MyApp</code><code>state</code>中的<code>inputValue</code>传入名为<code>input</code>的 prop。还要创建一个名为<code>handleChange</code>的 prop并将输入处理程序<code>handleChange</code>传递给它。
接下来,将<code>RenderInput</code>添加到<code>MyApp</code>中的 render 方法中,然后创建一个名为<code>input</code>的 prop并将<code>state</code>中的<code>inputValue</code>传递给它。完成后,你将能够在<code>GetInput</code>组件中的<code>input</code>字段中键入内容,然后该组件通过 props 调用其父组件中的处理函数方法。这将更新处于父组件<code>state</code>中的 input该 input 将作为 props 传递给两个子组件。观察数据如何在组件之间流动,以及单一数据源如何保持父组件<code>state</code>。诚然,这个示例有点做作,但是应该能用来说明数据和回调是如何在 React 组件之间传递的。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyApp</code>组件应该呈现
- text: 应该渲染<code>MyApp</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyApp)); return mockedComponent.find('MyApp').length === 1; })());
- text: <code>GetInput</code>组件应该呈现
- text: 应该渲染<code>GetInput</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyApp)); return mockedComponent.find('GetInput').length === 1; })());
- text: <code>RenderInput</code>组件应该呈现
- text: 应该渲染<code>RenderInput</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyApp)); return mockedComponent.find('RenderInput').length === 1; })());
- text: <code>GetInput</code>组件应该<code>MyApp</code>状态属性<code>inputValue</code>作为props接收,并包含一个修改<code>MyApp</code>状态的<code>input</code>元素。
- text: <code>GetInput</code>组件应该接收<code>MyApp</code>的 state 属性<code>inputValue</code>作为 props并包含一个修改<code>MyApp</code>state 的<code>input</code>元素。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyApp)); const state_1 = () => { mockedComponent.setState({inputValue: ''''}); return waitForIt(() => mockedComponent.state() )}; const state_2 = () => { mockedComponent.find(''input'').simulate(''change'', {target: {value: ''TestInput''}}); return waitForIt(() => mockedComponent.state() )}; const updated_1 = await state_1(); const updated_2 = await state_2(); assert(updated_1.inputValue === '''' && updated_2.inputValue === ''TestInput''); }; '
- text: <code>RenderInput</code>组件应该<code>MyApp</code>状态属性<code>inputValue</code>作为props接收
- text: <code>RenderInput</code>组件应该接收<code>MyApp</code>state 属性<code>inputValue</code>作为 props。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyApp)); const state_1 = () => { mockedComponent.setState({inputValue: ''TestName''}); return waitForIt(() => mockedComponent )}; const updated_1 = await state_1(); assert(updated_1.find(''p'').text().includes(''TestName'')); }; '
```
@ -43,7 +48,7 @@ class MyApp extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: "
inputValue: ''
}
this.handleChange = this.handleChange.bind(this);
}
@ -92,7 +97,6 @@ class RenderInput extends React.Component {
);
}
};
```
</div>
@ -102,7 +106,7 @@ class RenderInput extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyApp />, document.getElementById('root'))
```
</div>
@ -112,8 +116,63 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyApp extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: ''
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
inputValue: event.target.value
});
}
render() {
return (
<div>
<GetInput
input={this.state.inputValue}
handleChange={this.handleChange}/>
<RenderInput
input={this.state.inputValue}/>
</div>
);
}
};
class GetInput extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>Get Input:</h3>
<input
value={this.props.input}
onChange={this.props.handleChange}/>
</div>
);
}
};
class RenderInput extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>Input Render:</h3>
<p>{this.props.input}</p>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,34 +3,50 @@ id: 5a24c314108439a4d403616a
title: Pass an Array as Props
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 将数组作为道具传递
forumTopicId: 301401
localeTitle: 传递一个数组作为 Props
---
## Description
<section id="description">最后一项挑战演示了如何将信息从父组件传递到子组件作为<code>props</code>或属性。这个挑战着眼于如何将数组作为<code>props</code>传递。要将数组传递给JSX元素必须将其视为JavaScript并用大括号括起来。 <blockquote> &lt;为父级&gt; <br> &lt;ChildComponent colors = {[“green”“blue”“red”]} /&gt; <br> &lt;/为父级&gt; </blockquote>然后子组件可以访问数组属性<code>colors</code> 。访问属性时可以使用诸如<code>join()</code>类的数组方法。 <code>const ChildComponent = (props) =&gt; &lt;p&gt;{props.colors.join(&#39;, &#39;)}&lt;/p&gt;</code>这会将所有<code>colors</code>数组项连接成逗号分隔的字符串并生成: <code>&lt;p&gt;green, blue, red&lt;/p&gt;</code>稍后我们将了解在React中呈现数据数组的其他常用方法。 </section>
<section id='description'>
上一个挑战演示了如何将来自父组件的信息作为<code>props</code>传递给子组件。这个挑战着眼于如何将数组作为<code>props</code>传递。要将数组传递给 JSX 元素,必须将其视为 JavaScript 并用花括号括起来。
```jsx
<ParentComponent>
<ChildComponent colors={["green", "blue", "red"]} />
</ParentComponent>
```
这样,子组件就可以访问数组属性<code>colors</code>。访问属性时可以使用<code>join()</code>等数组方法。
<code>const ChildComponent = (props) => &lt;p&gt{props.colors.join(', ')}&lt;/p&gt</code>
这将把所有<code>colors</code>数组项连接成一个逗号分隔的字符串并生成:
<code> &lt;p&gt;green, blue, red&lt;/p&gt;</code>
稍后,我们将了解在 React 中渲染数组数据的其他常用方法。
</section>
## Instructions
<section id="instructions">代码编辑器中有<code>List</code><code>ToDo</code>组件。从<code>ToDo</code>组件渲染每个<code>List</code> ,传入分配给待办任务数组的<code>tasks</code>属性,例如<code>[&quot;walk dog&quot;, &quot;workout&quot;]</code> 。然后在<code>List</code>组件中访问此<code>tasks</code>数组,在<code>p</code>元素中显示其值。使用<code>join(&quot;, &quot;)</code>以逗号分隔列表的形式显示<code>p</code>元素中的<code>props.tasks</code>数组。今天的列表应该至少有2个任务明天应该至少有3个任务。 </section>
<section id='instructions'>
代码编辑器中有<code>List</code><code>ToDo</code>组件。在<code>ToDo</code>组件中渲染每个<code>List</code>时,传入<code>tasks</code>属性并将其分配给待办任务数组,例如<code>["walk dog", "workout"]</code>。然后访问<code>List</code>组件中的<code>tasks</code>数组,在<code>p</code>元素中显示其值。使用<code>join(", ")</code><code>props.tasks</code>数组作为逗号分隔列表显示在<code>p</code>元素中。今天的列表应该至少有 2 个任务,明天应该至少有 3 个任务。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>ToDo</code>组件应返回单个外部<code>div</code>
- text: <code>ToDo</code>组件应返回单个外部<code>div</code>。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.children().first().type() === 'div'; })());
- text: <code>ToDo</code>组件的第三个子<code>ToDo</code>应该是<code>List</code>组件的实例。
- text: <code>ToDo</code>组件的第三个子元素应该是<code>List</code>组件的一个实例。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.children().first().childAt(2).name() === 'List'; })());
- text: <code>ToDo</code>组件的第五个子<code>ToDo</code>应该是<code>List</code>组件的一个实例。
- text: <code>ToDo</code>组件的第五个子元素应该是<code>List</code>组件的一个实例。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.children().first().childAt(4).name() === 'List'; })());
- text: <code>List</code>组件的两个实例都应该有一个名为<code>tasks</code>的属性,<code>tasks</code>应该是array类型
- text: <code>List</code>组件的两个实例都应该有一个名为<code>tasks</code>的属性,并且<code>tasks</code>的类型应该是数组
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return Array.isArray(mockedComponent.find('List').get(0).props.tasks) && Array.isArray(mockedComponent.find('List').get(1).props.tasks); })());
- text: 表示今天任务的第一个<code>List</code>组件应该有2个或更多项。
- text: 表示今天任务的第一个<code>List</code>组件应该有 2 个或更多项。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.find('List').get(0).props.tasks.length >= 2; })());
- text: 表示明天任务的第二个<code>List</code>组件应该有3个或更多项。
- text: 表示明天任务的第二个<code>List</code>组件应该有 3 个或更多项。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.find('List').get(1).props.tasks.length >= 3; })());
- text: '<code>List</code>组件应该将<code>p</code>标记中的<code>tasks</code> prop的值呈现为以逗号分隔的列表例如<code>walk dog, workout</code> 。'
- text: <code>List</code>组件应<code>p</code>标签中渲染<code>tasks</code>属性的值。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.find('p').get(0).props.children === mockedComponent.find('List').get(0).props.tasks.join(', ') && mockedComponent.find('p').get(1).props.children === mockedComponent.find('List').get(1).props.tasks.join(', '); })());
```
@ -43,7 +59,7 @@ tests:
<div id='jsx-seed'>
```jsx
const List= (props) => {
const List = (props) => {
{ /* change code below this line */ }
return <p>{}</p>
{ /* change code above this line */ }
@ -67,7 +83,6 @@ class ToDo extends React.Component {
);
}
};
```
</div>
@ -77,7 +92,7 @@ class ToDo extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<ToDo />, document.getElementById('root'))
```
</div>
@ -87,8 +102,28 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const List= (props) => {
return <p>{props.tasks.join(', ')}</p>
};
class ToDo extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>To Do Lists</h1>
<h2>Today</h2>
<List tasks={['study', 'exercise']} />
<h2>Tomorrow</h2>
<List tasks={['call Sam', 'grocery shopping', 'order tickets']} />
</div>
);
}
};
```
/section>
</section>

View File

@ -3,31 +3,52 @@ id: 5a24c314108439a4d4036169
title: Pass Props to a Stateless Functional Component
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 将道具传递给无状态功能组件
forumTopicId: 301402
localeTitle: 将 Props 传递给无状态函数组件
---
## Description
<section id="description">之前的挑战涉及在React中创建和组合JSX元素功能组件和ES6样式类组件的很多内容。有了这个基础现在是时候看看React中常见的另一个特性 <b>道具</b> 。在React中您可以将props或属性传递给子组件。假设您有一个<code>App</code>组件,它呈现一个名为<code>Welcome</code>的子组件,它是一个无状态功能组件。您可以通过编写以下方式传递<code>Welcome</code> <code>user</code>属性: <blockquote> &lt;应用&gt; <br> &lt;Welcome user =&#39;Mark&#39;/&gt; <br> &lt;/应用&gt; </blockquote>您使用React提供支持的<strong>自定义HTML属性</strong> ,以将属性<code>user</code>传递给组件<code>Welcome</code> 。由于<code>Welcome</code>是一个无状态功能组件,因此它可以访问此值,如下所示: <blockquote> const Welcome =props=&gt; &lt;h1&gt; Hello{props.user}&lt;/ h1&gt; </blockquote>调用此值<code>props</code>是标准的在处理无状态函数组件时您基本上将其视为返回JSX的函数的参数。您可以在函数体中访问参数的值。使用类组件您会发现这有点不同。 </section>
<section id='description'>
之前的挑战涵盖了关于在 React 中创建和组合 JSX 元素、函数组件和 ES6 风格的类组件的很多内容。有了这个基础,现在是时候看看 React 中的另一个常见特性 <b>props</b> 了。在 React 中,你可以将属性传递给子组件。假设你有一个<code>App</code>组件,该组件渲染了一个名为<code>Welcome</code>的子组件,它是一个无状态函数组件。你可以通过以下方式给<code>Welcome</code>传递一个<code>user</code>属性:
```jsx
<App>
<Welcome user='Mark' />
</App>
```
使用<strong>自定义 HTML 属性</strong>React 支持将属性<code>user</code>传递给组件<code>Welcome</code>。由于<code>Welcome</code>是一个无状态函数组件,它可以像这样访问该值:
```jsx
const Welcome = (props) => <h1>Hello, {props.user}!</h1>
```
调用<code>props</code>这个值是常见做法,当处理无状态函数组件时,你基本上可以将其视为返回 JSX 的函数的参数。这样,你就可以在函数体中访问该值。但对于类组件,访问方式会略有不同。
</section>
## Instructions
<section id="instructions">代码编辑器中有<code>Calendar</code><code>CurrentDate</code>组件。当渲染<code>CurrentDate</code><code>Calendar</code>组件,通过在属性<code>date</code>分配给从JavaScript的当前日期<code>Date</code>对象。然后在<code>CurrentDate</code>组件中访问此<code>prop</code> ,在<code>p</code>标签中显示其值。请注意对于要作为JavaScript计算的<code>prop</code>值,它们必须用大括号括起来,例如<code>date={Date()}</code></section>
<section id='instructions'>
代码编辑器中有<code>Calendar</code><code>CurrentDate</code>组件。从<code>Calendar</code>组件渲染<code>CurrentDate</code>时,从 JavaScript 的<code>Date</code>对象分配当前日期,并将其作为<code>date</code>属性传入。然后访问<code>CurrentDate</code>组件的<code>prop</code>,并在<code>p</code>标签中显示其值。请注意,要将<code>prop</code>的值视为 JavaScript必须将它们括在花括号中例如<code>date={Date()}</code>
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>Calendar</code>组件应返回单个<code>div</code>元素。
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); return mockedComponent.children().type() === "div"; })(), "The <code>Calendar</code> component should return a single <code>div</code> element.");'
- text: <code>Calendar</code>组件的第二个子<code>CurrentDate</code>应该是<code>CurrentDate</code>组件。
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); return mockedComponent.children().childAt(1).name() === "CurrentDate"; })(), "The second child of the <code>Calendar</code> component should be the <code>CurrentDate</code> component.");'
- text: <code>CurrentDate</code>组件应该有一个名为<code>date</code>的prop
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); return mockedComponent.children().childAt(1).props().date })(), "The <code>CurrentDate</code> component should have a prop called <code>date</code>.");'
- text: <code>CurrentDate</code>的<code>date</code>道具应包含一文本。
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); const prop = mockedComponent.children().childAt(1).props().date; return( typeof prop === "string" && prop.length > 0 ); })(), "The <code>date</code> prop of the <code>CurrentDate</code> should contain a string of text.");'
- text: <code>CurrentDate</code>组件应该<code>p</code>标记中的<code>date</code>道具中呈现值
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); return mockedComponent.find("p").html().includes(Date().substr(3)); })(), "The <code>CurrentDate</code> component should render the value from the <code>date</code> prop in the <code>p</code> tag.");'
- text: <code>Calendar</code>组件应返回单个<code>div</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); return mockedComponent.children().type() === 'div'; })());
- text: <code>Calendar</code>组件的第二个子元素应该是<code>CurrentDate</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); return mockedComponent.children().childAt(1).name() === 'CurrentDate'; })());
- text: <code>CurrentDate</code>组件应该有一个名为<code>date</code>的属性
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); return mockedComponent.children().childAt(1).props().date })());
- text: <code>CurrentDate</code>的<code>date</code>属性应该包含一文本字符串
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); const prop = mockedComponent.children().childAt(1).props().date; return( typeof prop === 'string' && prop.length > 0 ); })());
- text: <code>CurrentDate</code>组件应该<code>date</code>属性渲染在<code>p</code>标签内
testString: assert(/<CurrentDatedate={Date\(\)}\/>/.test(code.replace(/\s/g, '')))
- text: <code>CurrentDate</code> 组件应该把 <code>date</code> 属性渲染在 <code>p</code> 标签内。
testString: let date = "dummy date"; assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CurrentDate, {date})); return mockedComponent.find('p').html().includes(date); })());
```
@ -39,6 +60,7 @@ tests:
<div id='jsx-seed'>
```jsx
const CurrentDate = (props) => {
return (
<div>
@ -64,7 +86,6 @@ class Calendar extends React.Component {
);
}
};
```
</div>
@ -74,7 +95,7 @@ class Calendar extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<Calendar />, document.getElementById('root'))
```
</div>
@ -84,8 +105,33 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const CurrentDate = (props) => {
return (
<div>
{ /* change code below this line */ }
<p>The current date is: {props.date}</p>
{ /* change code above this line */ }
</div>
);
};
class Calendar extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>What date is it?</h3>
{ /* change code below this line */ }
<CurrentDate date={Date()} />
{ /* change code above this line */ }
</div>
);
}
};
```
/section>
</section>

View File

@ -3,26 +3,32 @@ id: 5a24c314108439a4d403617a
title: Pass State as Props to Child Components
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 将状态作为道具传递给子组件
forumTopicId: 301403
localeTitle: 将 State 作为 Props 传递给子组件
---
## Description
<section id="description">您看到了许多在先前的挑战中将道具传递给子JSX元素和子React组件的示例。您可能想知道这些道具来自哪里。一种常见的模式是让一个有状态的组件包含对您的应用程序很重要的<code>state</code> ,然后呈现子组件。您希望这些组件可以访问该<code>state</code>某些部分这些部分作为props传递。例如您可能有一个<code>App</code>组件可以呈现<code>Navbar</code>以及其他组件。在您的<code>App</code> ,您的<code>state</code>包含大量用户信息,但<code>Navbar</code>只需要访问用户的用户名,以便显示它。您将该<code>state</code>作为prop传递给<code>Navbar</code>组件。这种模式说明了React中的一些重要范例。第一种是<em>单向数据流</em> 。状态沿着应用程序组件树的一个方向流动从有状态父组件到子组件。子组件仅接收所需的状态数据。第二复杂的有状态应用程序可以分解为几个或者一个有状态的组件。其余组件只是从父级接收状态作为props并从该状态呈现UI。它开始创建一个分离其中状态管理在代码的一部分中处理而UI在另一部分中呈现。将状态逻辑与UI逻辑分离的原则是React的关键原则之一。当它被正确使用时它使复杂的有状态应用程序的设计更容易管理。 </section>
<section id='description'>
在之前的挑战中,你看到了很多将 props 传递给子 JSX 元素和子 React 组件的例子。你可能想知道那些 props 是从哪里来的。一个常见的模式是:有状态组件中包含对应用程序很重要的<code>state</code>,然后用它渲染子组件。你希望这些组件能够访问该<code>state</code>的某些部分,就把这些部分作为 props 传入。
例如,也许你有一个<code>App</code>组件可以渲染<code>Navbar</code>以及其他组件。在你的<code>App</code>中,你的<code>state</code>中包含大量用户信息,但是<code>Navbar</code>只需要访问用户的用户名就可以显示出来,这时你将该<code>state</code>作为一个 prop 传递给<code>Navbar</code>组件即可。
这个模式说明了 React 中的一些重要范例。第一个是<em>单向数据流</em>state 沿着应用程序组件树的一个方向流动,从有状态父组件到子组件,子组件只接收它们需要的 state 数据。第二,复杂的有状态应用程序可以分解成几个,或者可能是一个单一的有状态组件。其余组件只是从父组件简单的接收 state 作为 props并从该 state 渲染 UI。它开始创建一种分离在这种分离中state 管理在代码的一部分中处理,而 UI 渲染在另一部分中处理。将 state 逻辑与 UI 逻辑分离是 React 的关键原则之一。当它被正确使用时,它使得复杂的、有状态的应用程序的设计变得更容易管理。
</section>
## Instructions
<section id="instructions"> <code>MyApp</code>组件是有状态的,并将<code>Navbar</code>组件呈现为子组件。将<code>name</code>属性的<code>state</code>向下传递给子组件,然后在<code>h1</code>标记中显示该<code>name</code> ,该<code>name</code><code>Navbar</code> render方法的一部分。 </section>
<section id='instructions'>
<code>MyApp</code>组件是有状态的,它将<code>Navbar</code>组件渲染成它的为子组件。将<code>MyApp</code>组件<code>state</code>中的<code>name</code>属性向下传递给子组件,然后在<code>h1</code>标签中显示<code>name</code><code>name</code><code>Navbar</code>render 方法的一部分。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyApp</code>组件应该使用内部的<code>Navbar</code>组件进行渲染
- text: <code>MyApp</code>组件应该在内部渲染一个<code>Navbar</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyApp)); return mockedComponent.find('MyApp').length === 1 && mockedComponent.find('Navbar').length === 1; })());
- text: <code>Navbar</code>组件应该<code>MyApp</code>状态属性<code>name</code>作为props接收
- text: <code>Navbar</code>组件应该接收<code>Navbar</code>的 state 中的<code>name</code>属性作为 props。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyApp)); const setState = () => { mockedComponent.setState({name: ''TestName''}); return waitForIt(() => mockedComponent.find(''Navbar'').props() )}; const navProps = await setState(); assert(navProps.name === ''TestName''); }; '
- text: <code>Navbar</code>的<code>h1</code>元素应该呈现<code>name</code> prop
- text: <code>Navbar</code>的<code>h1</code>元素应该渲染 prop<code>name</code>。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyApp)); const navH1Before = mockedComponent.find(''Navbar'').find(''h1'').text(); const setState = () => { mockedComponent.setState({name: ''TestName''}); return waitForIt(() => mockedComponent.find(''Navbar'').find(''h1'').text() )}; const navH1After = await setState(); assert(new RegExp(''TestName'').test(navH1After) && navH1After !== navH1Before); }; '
```
@ -58,12 +64,11 @@ class Navbar extends React.Component {
render() {
return (
<div>
<h1>Hello, my name is: /* your code here */ </h1>
<h1>Hello, my name is: {/* your code here */} </h1>
</div>
);
}
};
```
</div>
@ -73,7 +78,7 @@ class Navbar extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyApp />, document.getElementById('root'))
```
</div>
@ -83,8 +88,35 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyApp extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'CamperBot'
}
}
render() {
return (
<div>
<Navbar name={this.state.name}/>
</div>
);
}
};
class Navbar extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>Hello, my name is: {this.props.name}</h1>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,28 +3,34 @@ id: 5a24c314108439a4d4036167
title: Render a Class Component to the DOM
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 将类组件渲染到DOM
forumTopicId: 301404
localeTitle: 渲染 class 组件为 Dom 树
---
## Description
<section id="description">您可能还记得在早期挑战中使用ReactDOM API将JSX元素呈现给DOM。渲染React组件的过程看起来非常相似。过去的几个挑战集中在组件和组合上因此渲染是在幕后为您完成的。但是您编写的React代码都不会在不调用ReactDOM API的情况下呈现给DOM。这是对语法的更新 <code>ReactDOM.render(componentToRender, targetNode)</code> 。第一个参数是要呈现的React组件。第二个参数是要在其中呈现该组件的DOM节点。 React组件传递到<code>ReactDOM.render()</code>与JSX元素略有不同。对于JSX元素您传入要呈现的元素的名称。但是对于React组件您需要使用与渲染嵌套组件相同的语法例如<code>ReactDOM.render(&lt;ComponentToRender /&gt;, targetNode)</code> 。您可以将此语法用于ES6类组件和功能组件。 </section>
<section id='description'>
你可能还记得在早期挑战中使用 ReactDOM API 将 JSX 元素渲染到 DOM这与渲染 React 组件的过程十分相似。过去的几个挑战主要针对组件和组合,因此渲染是在幕后为你完成的。但是,如果不调用 ReactDOM API你编写的任何 React 代码都不会渲染到 DOM。
以下是语法的复习:<code>ReactDOM.render(componentToRender, targetNode)</code>。第一个参数是要渲染的 React 组件。第二个参数是要在其中渲染该组件的 DOM 节点。
React 组件传递到<code>ReactDOM.render()</code>与 JSX 元素略有不同。对于 JSX 元素,你传入的是要渲染的元素的名称。但是,对于 React 组件,你需要使用与渲染嵌套组件相同的语法,例如<code>ReactDOM.render(&lt;ComponentToRender /&gt;, targetNode)</code>。你可以将此语法用于ES6类组件和函数组件。
</section>
## Instructions
<section id="instructions"> <code>Fruits</code><code>Vegetables</code>组件都是在幕后为您定义的。将两个组件渲染为<code>TypesOfFood</code>组件的<code>TypesOfFood</code>组件,然后将<code>TypesOfFood</code>呈现给DOM。有一个<code>div</code> <code>id=&#39;challenge-node&#39;</code>可供您使用。 </section>
<section id='instructions'>
在后台为你定义了<code>Fruits</code><code>Vegetables</code>组件。将两个组件渲染为<code>TypesOfFood</code>组件的子组件,然后将<code>TypesOfFood</code>渲染到 DOM 节点,在这个挑战中,请渲染到 id 为<code>challenge-node</code><code>div</code>中。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>TypesOfFood</code>组件应返回单个<code>div</code>元素。
- text: <code>TypesOfFood</code>组件应返回单个<code>div</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().type() === 'div'; })());
- text: <code>TypesOfFood</code>组件应该在<code>h1</code>元素之后呈现<code>Fruits</code>组件。
- text: <code>TypesOfFood</code>组件应该在<code>h1</code>元素之后渲染<code>Fruits</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().childAt(1).name() === 'Fruits'; })());
- text: <code>TypesOfFood</code>组件应该在<code>Fruits</code>之后呈现<code>Vegetables</code>组件。
- text: <code>TypesOfFood</code>组件应该在<code>Fruits</code>组件之后渲染<code>Vegetables</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().childAt(2).name() === 'Vegetables'; })());
- text: <code>TypesOfFood</code>组件应该使用id <code>challenge-node</code>呈现给<code>div</code>的DOM
- text: <code>TypesOfFood</code>组件应该渲染到 id <code>challenge-node</code><code>div</code>
testString: assert((function() { const html = document.getElementById('challenge-node').childNodes[0].innerHTML; return html.includes('<div><h2>Fruits:</h2><h4>Non-Citrus:</h4><ul><li>Apples</li><li>Blueberries</li><li>Strawberries</li><li>Bananas</li></ul><h4>Citrus:</h4><ul><li>Lemon</li><li>Lime</li><li>Orange</li><li>Grapefruit</li></ul></div>') && html.includes('<div><h2>Vegetables:</h2><ul><li>Brussel Sprouts</li><li>Broccoli</li><li>Squash</li></ul></div>'); })());
```
@ -37,6 +43,7 @@ tests:
<div id='jsx-seed'>
```jsx
class TypesOfFood extends React.Component {
constructor(props) {
super(props);
@ -63,6 +70,7 @@ class TypesOfFood extends React.Component {
<div id='jsx-setup'>
```jsx
const Fruits = () => {
return (
<div>
@ -107,8 +115,27 @@ const Vegetables = () => {
## Solution
<section id='solution'>
```js
// solution required
class TypesOfFood extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>Types of Food:</h1>
{/* change code below this line */}
<Fruits />
<Vegetables />
{/* change code above this line */}
</div>
);
}
};
// change code below this line
ReactDOM.render(<TypesOfFood />, document.getElementById('challenge-node'));
```
/section>
</section>

View File

@ -3,34 +3,41 @@ id: 5a24c314108439a4d4036188
title: Render Conditionally from Props
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 从道具有条地渲染
forumTopicId: 301405
localeTitle: 根据 Props 有条地渲染
---
## Description
<section id="description">到目前为止,您已经了解了如何使用<code>if/else</code> <code>&amp;&amp;,</code> <code>null</code>和三元运算符( <code>condition ? expressionIfTrue : expressionIfFalse</code> 来做出有关呈现内容和何时呈现的条件决策。但是还有一个重要的话题要讨论它可以让你将这些概念中的任何一个或全部与另一个强大的React功能结合起来道具。使用props来有条件地呈现代码对于React开发人员来说非常普遍 - 也就是说他们使用给定prop的值来自动决定渲染内容。在此挑战中您将设置子组件以根据道具进行渲染决策。您还将使用三元运算符但您可以看到在最后几个挑战中涵盖的其他几个概念在此上下文中可能同样有用。 </section>
<section id='description'>
到目前为止,你已经看到了如何使用<code>if/else</code><code>&&,</code><code>null</code>和三元运算符(<code>condition ? expressionIfTrue : expressionIfFalse</code>)对渲染什么和何时渲染做出有条件的判定。然而,还有一个重要的话题需要讨论,让你将这些概念中的任何一个或所有概念与另一个强大的 React 功能结合起来props。使用 props 有条件地渲染代码在 React 开发人员中很常见--也就是说:他们使用给定 prop 的值来自动决定渲染什么。
在这个挑战中,你将设置一个子组件来根据 props 做出渲染决定。你可以使用三元运算符,但是你可以看到过去几个挑战中涵盖的其他几个概念在这种情况下可能同样有用。
</section>
## Instructions
<section id="instructions">代码编辑器有两个部分为您定义的组件:名为<code>GameOfChance</code>的父<code>GameOfChance</code>和名为<code>Results</code>的子级。它们用于创建一个简单的游戏,用户按下按钮以查看它们是赢还是输。首先,您需要一个简单的表达式,每次运行时都会随机返回一个不同的值。您可以使用<code>Math.random()</code> 。每次调用此方法时,此方法返回<code>0</code> (包括)和<code>1</code> 不包括之间的值。因此对于50/50赔率请在表达式中使用<code>Math.random() &gt; .5</code> 。从统计学上讲这个表达式将在50的时间内返回<code>true</code> 而在其他50时则返回<code>false</code> 。在第30行用此表达式替换注释以完成变量声明。现在您有了一个表达式您可以使用该表达式在代码中做出随机决策。接下来您需要实现此功能。将<code>Results</code>组件渲染为<code>GameOfChance</code>的子<code>GameOfChance</code> ,并将<code>expression</code>作为名为<code>fiftyFifty</code>的prop <code>fiftyFifty</code> 。在<code>Results</code>组件中,编写一个三元表达式来呈现文本<code>&quot;You win!&quot;</code>或者<code>&quot;You lose!&quot;</code>基于从<code>GameOfChance</code>传入的<code>fiftyFifty</code>道具。最后,确保<code>handleClick()</code>方法正确计算每个回合,以便用户知道他们玩了多少次。这也用于让用户知道组件已经实际更新,以防它们连续两次赢或输。 </section>
<section id='instructions'>
代码编辑器有两个部分为你定义的组件:一个名为<code>GameOfChance</code>的父组件和一个名为<code>Results</code>的子组件。他们被用来创建一个简单的游戏,用户按下按钮来看他们是赢还是输。
首先,你需要一个简单的表达式,每次运行时都会随机返回一个不同的值。你可以使用<code>Math.random()</code>。每次调用此方法时,此方法返回<code>0</code>(包括)和<code>1</code>不包括之间的值。因此对于50/50的几率请在表达式中使用<code>Math.random() > .5</code>。从统计学上讲,这个表达式有 50 的几率返回<code>true</code>,另外 50 返回<code>false</code>。在第 30 行,用此表达式替换注释以完成变量声明。
现在你有了一个表达式,可以用来在代码中做出随机决定,接下来你需要实现以下功能:将<code>Results</code>组件渲染为<code>GameOfChance</code>的子组件,并将<code>expression</code>作为 prop 传递出去prop 的名字是<code>fiftyFifty</code>。在<code>Results</code>组件中,编写一个三元表达式基于从<code>GameOfChance</code>传来的 prop<code>fiftyFifty</code>来渲染文本<code>"You win!"</code>或者<code>"You lose!"</code>。最后,确保<code>handleClick()</code>方法正确计算每个回合,以便用户知道他们玩过多少次。这也可以让用户知道组件实际上已经更新,以防他们连续赢两次或输两次时自己不知道。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>GameOfChance</code>组件应存在并呈现给页面。
- text: <code>GameOfChance</code>组件应存在并渲染到页面。
testString: assert.strictEqual(Enzyme.mount(React.createElement(GameOfChance)).find('GameOfChance').length, 1);
- text: <code>GameOfChance</code>应返回单个<code>button</code>元素。
- text: <code>GameOfChance</code>应返回单个<code>button</code>元素。
testString: assert.strictEqual(Enzyme.mount(React.createElement(GameOfChance)).find('button').length, 1);
- text: <code>GameOfChance</code>应返回<code>Results</code>组件的个实例,其中有一个名为<code>fiftyFifty</code>的prop。
- text: <code>GameOfChance</code>应返回<code>Results</code>组件的个实例,有一个名为<code>fiftyFifty</code>的 prop。
testString: assert(Enzyme.mount(React.createElement(GameOfChance)).find('Results').length === 1 && Enzyme.mount(React.createElement(GameOfChance)).find('Results').props().hasOwnProperty('fiftyFifty') === true);
- text: 应该使用<code>counter</code>设置为值<code>1</code>的属性初始化<code>GameOfChance</code>状态
- text: <code>GameOfChance</code>的 state 应该使用值为<code>1</code>的<code>counter</code>属性来初始化
testString: assert.strictEqual(Enzyme.mount(React.createElement(GameOfChance)).state().counter, 1);
- text: '当<code>GameOfChance</code>组件首次呈现给DOM时应返回一个<code>p</code>元素,内部文本为<code>Turn: 1</code> 。'
- text: '当<code>GameOfChance</code>组件第一次渲染到 DOM 时,应返回一个<code>p</code>元素,内部文本为<code>Turn: 1</code>。'
testString: 'assert.strictEqual(Enzyme.mount(React.createElement(GameOfChance)).find(''p'').text(), ''Turn: 1'');'
- text: 每次单击该按钮时,计数器状态应增加1并且应将单个<code>p</code>元素呈现给包含文本“TurnN”的DOM其中N是计数器状态的值。
- text: '每次点击按钮counter 应该增加 1并且一个包含文本<code>"Turn: N"</code>的<code>p</code>元素应该渲染到DOM其中<code>N</code>是 counter 的值。'
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(GameOfChance)); const simulate = () => { comp.find(''button'').simulate(''click''); };const result = () => ({ count: comp.state(''counter''), text: comp.find(''p'').text() });const _1 = () => { simulate(); return waitForIt(() => result())}; const _2 = () => { simulate(); return waitForIt(() => result())}; const _3 = () => { simulate(); return waitForIt(() => result())}; const _4 = () => { simulate(); return waitForIt(() => result())}; const _5 = () => { simulate(); return waitForIt(() => result())}; const _1_val = await _1(); const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); const _5_val = await _5(); assert(_1_val.count === 2 && _1_val.text === ''Turn: 2'' && _2_val.count === 3 && _2_val.text === ''Turn: 3'' && _3_val.count === 4 && _3_val.text === ''Turn: 4'' && _4_val.count === 5 && _4_val.text === ''Turn: 5'' && _5_val.count === 6 && _5_val.text === ''Turn: 6''); }; '
- text: 首次将<code>GameOfChance</code>组件安装到DOM时每次单击该按钮时,应返回个<code>h1</code>元素,随机呈现<code>You Win!</code>或者<code>You Lose!</code>
- text: <code>GameOfChance</code>组件第一次挂载到 DOM时,每次按钮被点击,都应该返回个<code>h1</code>元素,元素中随机渲染<code>You Win!</code>或者<code>You Lose!</code>。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(GameOfChance)); const simulate = () => { comp.find(''button'').simulate(''click''); };const result = () => ({ h1: comp.find(''h1'').length, text: comp.find(''h1'').text() });const _1 = result(); const _2 = () => { simulate(); return waitForIt(() => result())}; const _3 = () => { simulate(); return waitForIt(() => result())}; const _4 = () => { simulate(); return waitForIt(() => result())}; const _5 = () => { simulate(); return waitForIt(() => result())}; const _6 = () => { simulate(); return waitForIt(() => result())}; const _7 = () => { simulate(); return waitForIt(() => result())}; const _8 = () => { simulate(); return waitForIt(() => result())}; const _9 = () => { simulate(); return waitForIt(() => result())}; const _10 = () => { simulate(); return waitForIt(() => result())}; const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); const _5_val = await _5(); const _6_val = await _6(); const _7_val = await _7(); const _8_val = await _8(); const _9_val = await _9(); const _10_val = await _10(); const __text = new Set([_1.text, _2_val.text, _3_val.text, _4_val.text, _5_val.text, _6_val.text, _7_val.text, _8_val.text, _9_val.text, _10_val.text]); const __h1 = new Set([_1.h1, _2_val.h1, _3_val.h1, _4_val.h1, _5_val.h1, _6_val.h1, _7_val.h1, _8_val.h1, _9_val.h1, _10_val.h1]); assert(__text.size === 2 && __h1.size === 1); }; '
```
@ -72,7 +79,7 @@ class GameOfChance extends React.Component {
});
}
render() {
let expression = null; // change code here
const expression = null; // change code here
return (
<div>
<button onClick={this.handleClick}>Play Again</button>
@ -84,7 +91,6 @@ class GameOfChance extends React.Component {
);
}
};
```
</div>
@ -94,7 +100,7 @@ class GameOfChance extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<GameOfChance />, document.getElementById('root'))
```
</div>
@ -104,8 +110,49 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class Results extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<h1>
{
this.props.fiftyFifty ?
'You Win!' :
'You Lose!'
}
</h1>
)
};
};
class GameOfChance extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 1
}
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
counter: this.state.counter + 1
});
}
render() {
const expression = Math.random() >= .5;
return (
<div>
<button onClick={this.handleClick}>Play Again</button>
<Results fiftyFifty={expression} />
<p>{'Turn: ' + this.state.counter}</p>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,15 +3,21 @@ id: 5a24bbe0dba28a8d3cbd4c5f
title: Render HTML Elements to the DOM
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: HTML元素渲染到DOM
forumTopicId: 301406
localeTitle: 渲染 HTML 元素DOM
---
## Description
<section id="description">到目前为止您已经了解到JSX是一种在JavaScript中编写可读HTML的便捷工具。使用React我们可以使用React的渲染API称为ReactDOM将此JSX直接渲染到HTML DOM。 ReactDOM提供了一种简单的方法来将React元素呈现给DOM如下所示 <code>ReactDOM.render(componentToRender, targetNode)</code> 其中第一个参数是要呈现的React元素或组件第二个参数是DOM节点您想要将组件渲染到。正如您所料必须在JSX元素声明之后调用<code>ReactDOM.render()</code> ,就像在使用它们之前必须声明变量一样。 </section>
<section id='description'>
到目前为止,你已经了解到 JSX 是一种在 JavaScript 中编写可读 HTML 的便捷工具。在 React 中,我们可以使用它的的渲染 APIReactDOM将此 JSX 直接渲染到 HTML DOM。
ReactDOM 提供了一个简单的方法来将 React 元素呈现给 DOM如下所示<code>ReactDOM.render(componentToRender, targetNode)</code>,其中第一个参数是要渲染的 React 元素或组件,第二个参数是要将组件渲染到的 DOM 节点。
如你所料,必须在 JSX 元素声明之后调用<code>ReactDOM.render()</code>,就像你在使用变量之前必须声明它一样。
</section>
## Instructions
<section id="instructions">代码编辑器有一个简单的JSX组件。使用<code>ReactDOM.render()</code>方法将此组件呈现给页面。您可以直接将定义的JSX元素作为第一个参数传递并使用<code>document.getElementById()</code>来选择要将其渲染到的DOM节点。有一个<code>div</code> <code>id=&#39;challenge-node&#39;</code>可供您使用。确保不要更改<code>JSX</code>常量。 </section>
<section id='instructions'>
代码编辑器有一个简单的 JSX 组件。使用<code>ReactDOM.render()</code>方法将该组件渲染到页面。可以将定义好的 JSX 元素直接作为第一个参数传入,并使用<code>document.getElementById()</code>来选择要渲染到的 DOM 节点,在这个挑战中,请渲染到 id 为<code>challenge-node</code><code>div</code>中。
</section>
## Tests
<section id='tests'>
@ -20,11 +26,11 @@ localeTitle: 将HTML元素渲染到DOM
tests:
- text: 常量<code>JSX</code>应该返回一个<code>div</code>元素。
testString: assert(JSX.type === 'div');
- text: <code>div</code>应包含一个<code>h1</code>标作为第一个元素。
- text: <code>div</code>应包含一个<code>h1</code>标作为第一个元素。
testString: assert(JSX.props.children[0].type === 'h1');
- text: <code>div</code>应该包含一个<code>p</code>标签作为第二个元素。
testString: assert(JSX.props.children[1].type === 'p');
- text: 提供的JSX元素应该使用id <code>challenge-node</code>呈现给DOM <code>challenge-node</code>
- text: 提供的 JSX 元素应该渲染到 id <code>challenge-node</code>DOM 节点
testString: assert(document.getElementById('challenge-node').childNodes[0].innerHTML === '<h1>Hello World</h1><p>Lets render this to the DOM</p>');
```
@ -56,8 +62,16 @@ const JSX = (
## Solution
<section id='solution'>
```js
// solution required
const JSX = (
<div>
<h1>Hello World</h1>
<p>Lets render this to the DOM</p>
</div>
);
// change code below this line
ReactDOM.render(JSX, document.getElementById('challenge-node'));
```
/section>
</section>

View File

@ -3,22 +3,27 @@ id: 5a24c314108439a4d403618d
title: Render React on the Server with renderToString
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用renderToString在服务器上渲染React
forumTopicId: 301407
localeTitle: 用 renderToString 在服务器上渲染 React
---
## Description
<section id="description">到目前为止您已在客户端上呈现React组件。通常这是你将永远做的。但是在某些用例中在服务器上呈现React组件是有意义的。由于React是一个JavaScript视图库您可以使用Node在服务器上运行JavaScript这是可能的。实际上React提供了一个<code>renderToString()</code>方法您可以将其用于此目的。有两个关键原因可以解释为什么服务器上的渲染可能会在真实世界的应用程序中使用。首先如果不这样做你的React应用程序将包含一个相对空的HTML文件和一大堆JavaScript当它最初加载到浏览器时。对于试图索引页面内容以便人们可以找到您的搜索引擎而言这可能并不理想。如果在服务器上呈现初始HTML标记并将其发送到客户端则初始页面加载包含搜索引擎可以抓取的所有页面标记。其次这会创建更快的初始页面加载体验因为呈现的HTML小于整个应用程序的JavaScript代码。 React仍然能够识别您的应用并在初始加载后进行管理。 </section>
<section id='description'>
到目前为止,你已经能够在客户端上渲染 React 组件,一般来说我们都是这么做的。然而,在一些用例中,在服务器上渲染一个 React 组件是有意义的。由于 React 是一个 JavaScript 视图库,所以使用 Node 让 JavaScript 运行在服务器上是可行的。事实上React 提供了一个可用于此目的的<code>renderToString()</code>方法。
有两个关键原因可以解释为什么服务器上的渲染可能会在真实世界的应用程序中使用。首先,如果不这样做,你的 React 应用程序将包含一个代码量很少的 HTML 文件和一大堆 JavaScript当它最初加载到浏览器时。这对于搜索引擎来说可能不太理想因为它们试图为你的网页内容生成索引以便人们可以找到你。如果在服务器上渲染初始 HTML 标记并将其发送到客户端,则初始页面加载的内容包含搜索引擎可以抓取的所有页面标记。其次,这创造了更快的初始页面加载体验,因为渲染的 HTML 代码量要比整个应用程序的 JavaScript 代码小。React 仍然能够识别你的应用并在初始加载后进行管理。
</section>
## Instructions
<section id="instructions"> <code>renderToString()</code>方法在<code>ReactDOMServer</code>上提供在此处可用作全局对象。该方法采用一个参数它是一个React元素。使用此选项将<code>App</code>呈现为字符串。 </section>
<section id='instructions'>
<code>renderToString()</code>方法由<code>ReactDOMServer</code>提供,在这里已为你定义成全局变量。这个方法接受一个 React 元素作为参数。用它来把<code>App</code>渲染成字符串。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>App</code>组件应使用<code>ReactDOMServer.renderToString</code>呈现为字符串。
- text: <code>App</code>组件应使用<code>ReactDOMServer.renderToString</code>渲染一个字符串。
testString: getUserInput => assert(getUserInput('index').replace(/ /g,'').includes('ReactDOMServer.renderToString(<App/>)') && Enzyme.mount(React.createElement(App)).children().name() === 'div');
```
@ -31,6 +36,7 @@ tests:
<div id='jsx-seed'>
```jsx
class App extends React.Component {
constructor(props) {
super(props);
@ -51,7 +57,6 @@ class App extends React.Component {
```jsx
var ReactDOMServer = { renderToString(x) { return null; } };
```
</div>
@ -60,7 +65,7 @@ var ReactDOMServer = { renderToString(x) { return null; } };
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<App />, document.getElementById('root'))
```
</div>
@ -70,8 +75,19 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return <div/>
}
};
// change code below this line
ReactDOMServer.renderToString(<App/>);
```
/section>
</section>

View File

@ -3,28 +3,33 @@ id: 5a24c314108439a4d4036172
title: Render State in the User Interface Another Way
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 用户界面中渲染状态另一种方式
forumTopicId: 301408
localeTitle: 以另一种方式在用户界面中渲染状态
---
## Description
<section id="description">还有另一种访问组件中<code>state</code>方法。在<code>render()</code>方法中,在<code>return</code>语句之前您可以直接编写JavaScript。例如您可以声明函数<code>state</code><code>props</code>访问数据,对此数据执行计算,等等。然后,您可以将任何数据分配给您可以在<code>return</code>语句中访问的变量。 </section>
<section id='description'>
还有另一种方法可以访问组件中的<code>state</code>。在<code>render()</code>方法中,在<code>return</code>语句之前,你可以直接编写 JavaScript。例如你可以声明函数、从<code>state</code><code>props</code>访问数据、对此数据执行计算等。然后,你可以将任何数据赋值给你在<code>return</code>语句中可以访问的变量。
</section>
## Instructions
<section id="instructions"><code>MyComponent</code> render方法中定义一个名为<code>name</code><code>const</code> ,并将其设置为等于组件<code>state</code>的name值。因为您可以直接在代码的这一部分编写JavaScript所以您不必将此引用括在花括号中。接下来在return语句中使用变量<code>name</code><code>h1</code>标记中呈现此值。请记住您需要在return语句中使用JSX语法JavaScript的大括号</section>
<section id='instructions'>
<code>MyComponent</code>的 render 方法中,定义一个名为<code>name</code><code>常量</code>,并将其设置为组件<code>state</code>中的 name 值。因为可以直接在代码部分编写 JavaScript所以不需要用大括号括起来。
接下来,在 return 语句中,在<code>h1</code>标签中渲染变量<code>name</code>的值。记住,在 return 语句中需要使用 JSX 语法(用到 JavaScript 的花括号)。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyComponent</code>应该有一个键<code>name</code> ,其<code>freeCodeCamp</code>存储在其状态中。
- text: <code>MyComponent</code>应该有一个键<code>name</code>,其<code>freeCodeCamp</code>存储在其 state 中。
testString: assert(Enzyme.mount(React.createElement(MyComponent)).state('name') === 'freeCodeCamp');
- text: <code>MyComponent</code>应该渲染一个包含在单个<code>div</code><code>h1</code>标
- text: <code>MyComponent</code>应该<code>div</code>中渲染一个<code>h1</code>标
testString: assert(/<div><h1>.*<\/h1><\/div>/.test(Enzyme.mount(React.createElement(MyComponent)).html()));
- text: '渲染的<code>h1</code>标记应包含<code>{name}</code>的引用。'
- text: 渲染的<code>h1</code>标签应该包含<code>{name}</code>的引用。
testString: getUserInput => assert(/<h1>\n*\s*\{\s*name\s*\}\s*\n*<\/h1>/.test(getUserInput('index')));
- text: 渲染的<code>h1</code>标头应包含从组件状态呈现的文本
- text: 渲染的<code>h1</code>标题中应该包含一段文本,这段文本是从组件的 state 中渲染出来的
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: ''TestName'' }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === ''<div><h1>TestName</h1></div>''); };'
```
@ -57,7 +62,6 @@ class MyComponent extends React.Component {
);
}
};
```
</div>
@ -67,7 +71,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -77,8 +81,28 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'freeCodeCamp'
}
}
render() {
// change code below this line
const name = this.state.name;
// change code above this line
return (
<div>
{ /* change code below this line */ }
<h1>{name}</h1>
{ /* change code above this line */ }
</div>
);
}
};
```
/section>
</section>

View File

@ -3,26 +3,34 @@ id: 5a24c314108439a4d4036171
title: Render State in the User Interface
challengeType: 6
isRequired: false
videoUrl: ''
forumTopicId: 301409
localeTitle: 在用户界面中渲染状态
---
## Description
<section id="description">定义组件的初始状态后可以在呈现的UI中显示它的任何部分。如果组件是有状态的它将始终可以访问其<code>render()</code>方法中的<code>state</code>数据。您可以使用<code>this.state</code>访问数据。如果要在render方法的<code>return</code>中访问状态值,则必须将值括在花括号中。 <code>State</code>是React中组件最强大的功能之一。它允许您跟踪应用程序中的重要数据并呈现UI以响应此数据中的更改。如果您的数据发生变化您的UI将会发生变化React使用所谓的虚拟DOM来跟踪幕后的变化。当状态数据更新时它会触发使用该数据重新呈现组件 - 包括作为道具接收数据的子组件。 React更新实际的DOM但仅在必要时更新。这意味着您不必担心更改DOM。您只需声明UI应该是什么样子。请注意如果使组件有状态则其他组件不会知道其<code>state</code> 。它的<code>state</code>是完全封装的,或者是该组件的本地状态,除非您将状态数据作为<code>props</code>传递给子组件。这种封装<code>state</code>概念非常重要,因为它允许您编写某些逻辑,然后在代码中的某个位置包含和隔离该逻辑。 </section>
<section id='description'>
一旦定义了组件的初始 state你就可以在要渲染的 UI 中显示它的任何部分。如果组件是有状态的,它将始终可以访问<code>render()</code>方法中<code>state</code>的数据。你就可以使用<code>this.state</code>访问数据。
如果你想在 render 方法的<code>return</code>中访问 state 值,你必须把这个值用花括号括起来。
<code>state</code>是 React 组件中最强大的特性之一,它允许你跟踪应用程序中的重要数据,并根据数据的变化渲染 UI。如果你的数据发生变化你的 UI 也会随之改变。React 使用所谓的虚拟 DOM 来跟踪幕后的变化。当 state 数据更新时,它会使用该数据触发组件的重新渲染--包括接收 prop 数据的子组件。React 只在必要的时候更新实际的DOM这意味着你不必担心 DOM 的变更,只需声明 UI 的外观即可。
注意,如果组件有状态,则没有其他组件知道它的<code>state</code>。它的<code>state</code>是完全封装的,或者是局限于组件本身的,除非你将 state 数据作为<code>props</code>传递给子组件。封装<code>state</code>的概念非常重要,因为它允许你编写特定的逻辑,然后将该逻辑包含并隔离在代码中的某个位置。
</section>
## Instructions
<section id="instructions">在代码编辑器中, <code>MyComponent</code>已经是有状态的。在组件的render方法中定义<code>h1</code>标记,该方法从组件的状态呈现<code>name</code>的值。 <strong>注意:</strong> <code>h1</code>应该只从<code>state</code>呈现值而不是其他内容。在JSX中您使用花括号<code>{ }</code>编写的任何代码都将被视为JavaScript。因此要从<code>state</code>访问值,只需将引用括在花括号中。 </section>
<section id='instructions'>
在代码编辑器中,<code>MyComponent</code>是一个有状态组件,在组件的 render 方法中定义一个<code>h1</code>标签,该方法从组件的 state 渲染<code>name</code>的值。
<strong>注意:</strong>&nbsp;<code>h1</code>应该只渲染来自<code>state</code>的值。在 JSX 中,使用花括号<code>{ }</code>编写的任何代码都将被视为 JavaScript。因此要访问<code>state</code>中的值,只需将引用括在花括号中即可。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyComponent</code>应该有一个键<code>name</code> ,其<code>freeCodeCamp</code>存储在其状态中。
- text: <code>MyComponent</code>应该有一个键<code>name</code>,其<code>freeCodeCamp</code>存储在其 state 中。
testString: assert(Enzyme.mount(React.createElement(MyComponent)).state('name') === 'freeCodeCamp');
- text: <code>MyComponent</code>应该渲染一个包含在单个<code>div</code><code>h1</code>标
- text: <code>MyComponent</code>应该<code>div</code>中渲染一个<code>h1</code>标
testString: assert(/<div><h1>.*<\/h1><\/div>/.test(Enzyme.mount(React.createElement(MyComponent)).html()));
- text: 渲染的<code>h1</code>标头应包含从组件状态呈现的文本
- text: 渲染的<code>h1</code>标题中应该包含一段文本,这段文本是从组件的 state 中渲染出来的
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: ''TestName'' }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === ''<div><h1>TestName</h1></div>'');};'
```
@ -52,7 +60,6 @@ class MyComponent extends React.Component {
);
}
};
```
</div>
@ -62,7 +69,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -72,8 +79,25 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'freeCodeCamp'
}
}
render() {
return (
<div>
{ /* change code below this line */ }
<h1>{this.state.name}</h1>
{ /* change code above this line */ }
</div>
);
}
};
```
/section>
</section>

View File

@ -3,28 +3,33 @@ id: 5a24c314108439a4d4036184
title: Render with an If-Else Condition
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用If-Else条件渲染
forumTopicId: 301410
localeTitle: 使用 If-Else 条件进行渲染
---
## Description
<section id="description">使用JavaScript控制渲染视图的另一个应用是将呈现的元素绑定到条件。当条件为真时一个视图呈现。当它是假的时它是一个不同的观点。您可以使用React组件的<code>render()</code>方法中的标准<code>if/else</code>语句执行此操作。 </section>
<section id='description'>
使用 JavaScript 控制渲染视图的另一个应用是将渲染的元素绑定到一个条件。当条件为真时,将呈现一个视图,反之,则呈现另一种视图。你可以在 React 组件的<code>render()</code>方法中使用的标准<code>if/else</code>语句来实现这一点。
</section>
## Instructions
<section id="instructions"> MyComponent在其状态中包含一个<code>boolean</code> 用于跟踪是否要在UI中显示某个元素。该<code>button</code>切换此值的状态。目前它每次都呈现相同的UI。使用<code>if/else</code>语句重写<code>render()</code>方法,以便如果<code>display</code><code>true</code> ,则返回当前标记。否则,返回没有<code>h1</code>元素的标记。 <strong>注意:</strong>您必须编写<code>if/else</code>以传递测试。使用三元运算符不会通过此处。 </section>
<section id='instructions'>
MyComponent 的 state 中包含一个<code>布尔值</code>,用于跟踪是否要在 UI 中显示某个元素。<code>按钮</code>切换此值的状态。目前,它每次都呈现相同的 UI。用<code>if/else</code>语句重写<code>render()</code>方法,如果<code>display</code><code>true</code>则返回当前标记。否则,返回不带<code>h1</code>元素的标记。
<strong>注意:</strong>&nbsp;<code>if/else</code>语句才能通过测试,使用三元运算符是不会通过的。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyComponent</code>应该存在并呈现
- text: <code>MyComponent</code>应该存在并被渲染
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find('MyComponent').length === 1; })());
- text: 当<code>display</code>设置为<code>true</code> ,应该渲染<code>div</code> <code>button</code>和<code>h1</code>
- text: 当<code>display</code>设置为<code>true</code>时,<code>div</code><code>button</code>和<code>h1</code>标签应该被渲染
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: true}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(mockedComponent.find(''div'').length === 1 && mockedComponent.find(''div'').children().length === 2 && mockedComponent.find(''button'').length === 1 && mockedComponent.find(''h1'').length === 1); }; '
- text: 当<code>display</code>设置为<code>false</code> ,只应呈现<code>div</code>和<code>button</code>
- text: 当<code>display</code>设置为<code>false</code>,只<code>div</code>和<code>button</code>应该被渲染
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: false}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(mockedComponent.find(''div'').length === 1 && mockedComponent.find(''div'').children().length === 1 && mockedComponent.find(''button'').length === 1 && mockedComponent.find(''h1'').length === 0); }; '
- text: render方法使用<code>if/else</code>语句来检查<code>this.state.display</code>的条件。
- text: render 方法中应该使用<code>if/else</code>语句来检查<code>this.state.display</code>的条件。
testString: getUserInput => assert(getUserInput('index').includes('if') && getUserInput('index').includes('else'));
```
@ -61,7 +66,6 @@ class MyComponent extends React.Component {
);
}
};
```
</div>
@ -71,7 +75,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -81,8 +85,39 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
display: true
}
this.toggleDisplay = this.toggleDisplay.bind(this);
}
toggleDisplay() {
this.setState({
display: !this.state.display
});
}
render() {
// change code below this line
if (this.state.display) {
return (
<div>
<button onClick={this.toggleDisplay}>Toggle Display</button>
<h1>Displayed!</h1>
</div>
);
} else {
return (
<div>
<button onClick={this.toggleDisplay}>Toggle Display</button>
</div>
);
}
}
};
```
/section>
</section>

View File

@ -3,30 +3,36 @@ id: 5a24c314108439a4d403616f
title: Review Using Props with Stateless Functional Components
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 查看使用无状态功能组件的道具
forumTopicId: 301411
localeTitle: 复习如何使用 Props 和无状态函数组件
---
## Description
<section id="description">除了最后的挑战,你已经将道具传递给无状态功能组件。这些组件就像纯函数一样。他们接受道具作为输入,并在每次传递相同的道具时返回相同的视图。您可能想知道状态是什么,下一个挑战将更详细地介绍它。在此之前,这里是对组件术语的回顾。 <em>无状态功能组件</em>是您编写的任何接受道具并返回JSX的函数。另一方面 <em>无状态组件</em>是扩展<code>React.Component</code>的类,但不使用内部状态(在下一个挑战中涵盖)。最后,有<em>状态组件</em>是保持其自身内部状态的任何组件。您可能会看到有状态组件简称为组件或React组件。一种常见的模式是尽可能地减少有状态并创建无状态功能组件。这有助于将状态管理包含到应用程序的特定区域。反过来通过更容易地了解状态更改如何影响其行为这可以改善应用程序的开发和维护。 </section>
<section id='description'>
除了上一个挑战,你一直在将 props 传递给无状态的函数组件。这些组件就像纯函数,它们接收 props 作为输入,并在每次传递相同 props 时返回相同的视图。你可能会想知道什么是状态,下一个挑战将会更详细地讲述它。在此之前,我们先来回顾一下组件的术语。
<em>无状态函数组件</em>是一个函数,它接收 props 作为输入并返回 JSX。另一方面<em>无状态组件</em>是一个类,它扩展了<code>React.Component</code>,但是不使用内部状态(下一个挑战中讨论)。最后,<em>状态组件</em>是指维护其自身内部状态的组件,它简称组件或 React 组件。
一种常见的应用模式是尽可能减少状态组件并创建无状态的函数组件。这有助于将状态管理包含到应用程序的特定区域。反过来,通过更容易地跟踪状态变化如何影响其行为,可以改进应用程序的开发和维护。
</section>
## Instructions
<section id="instructions">代码编辑器有一个<code>CampSite</code>组件,它将<code>Camper</code>组件呈现为子组件。定义<code>Camper</code>组件并为其指定<code>{ name: &#39;CamperBot&#39; }</code>默认道具。在<code>Camper</code>组件内部,渲染您想要的任何代码,但要确保有一个<code>p</code>元素仅包含作为<code>prop</code>传递的<code>name</code>值。最后,在<code>Camper</code>组件上定义<code>propTypes</code> ,要求将<code>name</code>作为prop提供并验证它是<code>string</code>类型。 </section>
<section id='instructions'>
在代码编辑器中有一个<code>CampSite</code>组件,它把<code>Camper</code>组件渲染为自己的子组件。定义<code>Camper</code>组件,并为其分配默认 props<code>{ name: 'CamperBot' }</code>。你可以在<code>Camper</code>组件内部渲染任何你想要的代码,但是要确保有一个<code>p</code>元素,它只包含作为<code>prop</code>传递的<code>name</code>值。最后,在<code>Camper</code>组件上定义<code>propTypes</code>,要求提供<code>name</code>作为 prop并验证它是<code>string</code>类型。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>CampSite</code>组件应该呈现
- text: 应该渲染<code>CampSite</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find('CampSite').length === 1; })());
- text: <code>Camper</code>组件应呈现
- text: 应该渲染<code>Camper</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find('Camper').length === 1; })());
- text: <code>Camper</code>组件应该包含默认道具,它将字符串<code>CamperBot</code>分配给键<code>name</code>
- text: <code>Camper</code>组件应该包含默认 props,它将字符串<code>CamperBot</code>赋值给关键字<code>name</code>。
testString: assert(/Camper.defaultProps={name:(['"`])CamperBot\1,?}/.test(code.replace(/\s/g, '')));
- text: <code>Camper</code>组件应包含要求<code>name</code> prop为<code>string</code>类型的prop类型
- text: <code>Camper</code>组件应包含<code>string</code>类型的<code>name</code>prop。
testString: assert(/Camper.propTypes={name:PropTypes.string.isRequired,?}/.test(code.replace(/\s/g, '')));
- text: <code>Camper</code>组件应包含一个<code>p</code>元素,其中只包含<code>name</code> prop的文本。
- text: <code>Camper</code>组件应包含一个<code>p</code>元素,元素内是来自prop<code>name</code>的唯一文本。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find('p').text() === mockedComponent.find('Camper').props().name; })());
```
@ -64,7 +70,6 @@ class CampSite extends React.Component {
var PropTypes = {
string: { isRequired: true }
};
```
</div>
@ -73,7 +78,7 @@ var PropTypes = {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<CampSite />, document.getElementById('root'))
```
</div>
@ -83,8 +88,38 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class CampSite extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<Camper/>
</div>
);
}
};
// change code below this line
const Camper = (props) => {
return (
<div>
<p>{props.name}</p>
</div>
);
};
Camper.propTypes = {
name: PropTypes.string.isRequired
};
Camper.defaultProps = {
name: 'CamperBot'
};
```
/section>
</section>

View File

@ -3,28 +3,41 @@ id: 5a24c314108439a4d4036173
title: Set State with this.setState
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用this.setState设置State
forumTopicId: 301412
localeTitle: 用 this.setState 设置状态
---
## Description
<section id="description">之前的挑战包括组件<code>state</code>以及如何在<code>constructor</code>初始化状态。还有一种方法可以改变组件的<code>state</code> 。 React提供了一种更新名为<code>setState</code>组件<code>state</code>的方法。您可以在组件类中调用<code>setState</code>方法,如下所示: <code>this.setState()</code> ,传入一个具有键值对的对象。键是您的状态属性,值是更新的状态数据。例如,如果我们在状态中存储<code>username</code>并想要更新它,它将如下所示: <blockquote> this.setState{ <br>用户名:&#39;Lewis&#39; <br> }; </blockquote> React希望你永远不要直接修改<code>state</code> ,而是在状态发生变化时总是使用<code>this.setState()</code> 。此外您应该注意React可以批量处理多个状态更新以提高性能。这意味着通过<code>setState</code>方法的状态更新可以是异步的。 <code>setState</code>方法有一种替代语法,它提供了解决此问题的方法。这很少需要,但记住它是件好事!有关更多详细信息,请参阅<a target="_blank" href="https://facebook.github.io/react/docs/state-and-lifecycle.html">React文档</a></section>
<section id='description'>
前面的挑战涵盖了组件的<code>state</code>以及如何在<code>constructor</code>中初始化 state。还有一种方法可以更改组件的<code>state</code>React 提供了<code>setState</code>方法来更新组件的<code>state</code>。在组件类中调用<code>setState</code>方法如下所示:<code>this.setState()</code>,传入键值对的对象,其中键是 state 属性,值是更新后的 state 数据。例如,如果我们在 state 中存储<code>username</code>,并想要更新它,代码如下所示:
```jsx
this.setState({
username: 'Lewis'
});
```
React 希望你永远不要直接修改<code>state</code>,而是在 state 发生改变时始终使用<code>this.setState()</code>。此外你应该注意React 可以批量处理多个 state 更新以提高性能。这意味着通过<code>setState</code>方法进行的 state 更新可以是异步的。<code>setState</code>方法有一种替代语法可以解决异步问题,虽然这很少用到,但是最好还是记住它!有关详细信息,请参阅<a target="_blank" href="https://facebook.github.io/react/docs/state-and-lifecycle.html">React 文档</a>
</section>
## Instructions
<section id="instructions">代码编辑器中有一个<code>button</code>元素,它有一个<code>onClick()</code>处理程序。当<code>button</code>在浏览器中收到单击事件时,将触发此处理程序,并运行<code>MyComponent</code>定义的<code>handleClick</code>方法。在<code>handleClick</code>方法中,使用<code>this.setState()</code>更新组件<code>state</code> 。设置<code>name</code>的属性<code>state</code>为等于字符串<code>React Rocks!</code> 。单击按钮并观察呈现的状态更新。如果您还不完全了解点击处理程序代码在此时的工作原理,请不要担心。它涵盖了即将到来的挑战。 </section>
<section id='instructions'>
代码编辑器中有一个<code>button</code>元素,它有一个<code>onClick()</code>处理程序。当<code>button</code>在浏览器中接收到单击事件时触发此处理程序,并运行<code>MyComponent</code>中定义的<code>handleClick</code>方法。在<code>handleClick</code>方法中,使用<code>this.setState()</code>更新组件的<code>state</code>。设置<code>state</code>中的<code>name</code>属性为字符串<code>React Rocks!</code>
单击按钮查看渲染的 state 的更新。如果你不完全理解单击处理程序代码在此时的工作方式,请不要担心。在接下来的挑战中会有讲述。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: '<code>MyComponent</code>的状态应使用键值对<code>{ name: Initial State }</code> 。'
- text: '<code>MyComponent</code>的 state 应该使用键值对 <code>{ name: Initial State }</code> 来初始化。'
testString: 'assert(Enzyme.mount(React.createElement(MyComponent)).state(''name'') === ''Initial State'');'
- text: <code>MyComponent</code>应该呈现一个<code>h1</code>标
- text: <code>MyComponent</code>应该渲染一个<code>h1</code>标
testString: assert(Enzyme.mount(React.createElement(MyComponent)).find('h1').length === 1);
- text: 渲染的<code>h1</code>标头应包含从组件状态呈现的文本
- text: 渲染的<code>h1</code>标题中应该包含一段文本,这段文本是从组件的 state 中渲染出来的
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: ''TestName'' }); return waitForIt(() => mockedComponent.html()); }; const firstValue = await first(); assert(/<h1>TestName<\/h1>/.test(firstValue)); };'
- text: <code>MyComponent</code>上调用<code>handleClick</code>方法应该将state属性设置为等于<code>React Rocks!</code>
- text: 调用<code>MyComponent</code><code>handleClick</code>方法应该将 state 的 name 属性设置为<code>React Rocks!</code>。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: ''Before'' }); return waitForIt(() => mockedComponent.state(''name'')); }; const second = () => { mockedComponent.instance().handleClick(); return waitForIt(() => mockedComponent.state(''name'')); }; const firstValue = await first(); const secondValue = await second(); assert(firstValue === ''Before'' && secondValue === ''React Rocks!''); };'
```
@ -59,7 +72,6 @@ class MyComponent extends React.Component {
);
}
};
```
</div>
@ -69,7 +81,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -79,8 +91,32 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'Initial State'
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// change code below this line
this.setState({
name: 'React Rocks!'
});
// change code above this line
}
render() {
return (
<div>
<button onClick = {this.handleClick}>Click Me</button>
<h1>{this.state.name}</h1>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,28 +3,34 @@ id: 5a24c314108439a4d4036185
title: Use && for a More Concise Conditional
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用&&获得更简洁的条件
forumTopicId: 301413
localeTitle: 使用 && 获得更简洁的条件
---
## Description
<section id="description"> if / else语句在最后一次挑战中起作用但是有一种更简洁的方法来实现相同的结果。想象一下您正在跟踪组件中的多个条件并且您希望根据这些条件中的每个条件呈现不同的元素。如果你写了很多<code>else if</code>语句来返回略有不同的UI你可能会重复代码这会留下错误的余地。相反您可以使用<code>&amp;&amp;</code> logical运算符以更简洁的方式执行条件逻辑。这是可能的因为您要检查条件是否为<code>true</code> ,如果是,则返回一些标记。下面是一个示例: <code>{condition &amp;&amp; &lt;p&gt;markup&lt;/p&gt;}</code>如果<code>condition</code><code>true</code> ,则返回标记。如果条件为<code>false</code> ,则在评估<code>condition</code>后操作将立即返回<code>false</code>并且不返回任何内容。您可以直接在JSX中包含这些语句并在每个语句之后写入<code>&amp;&amp;</code>多个条件串在一起。这允许您在<code>render()</code>方法中处理更复杂的条件逻辑,而无需重复大量代码。 </section>
<section id='description'>
if/else 语句在上一次挑战中是有效的,但是有一种更简洁的方法可以达到同样的结果。假设你正在跟踪组件中的几个条件,并且希望根据这些条件中的每一个来渲染不同的元素。如果你写了很多<code>else if</code>语句来返回稍微不同的 UI你可能会写很多重复代码这就留下了出错的空间。相反你可以使用<code>&&</code>逻辑运算符以更简洁的方式执行条件逻辑。这是完全可行的,因为你希望检查条件是否为真,如果为真,则返回一些标记。这里有一个例子:
<code>{condition && &lt;p&gt;markup&lt;/p&gt;}</code>
如果<code>condition</code>为 true则返回标记。如果 condition 为 false操作将在判断<code>condition</code>后立即返回<code>false</code>,并且不返回任何内容。你可以将这些语句直接包含在 JSX 中,并通过在每个条件后面写<code>&&</code>来将多个条件串在一起。这允许你在<code>render()</code>方法中处理更复杂的条件逻辑,而无需重复大量代码。
</section>
## Instructions
<section id="instructions">再次解决前面的示例,因此<code>h1</code>仅在<code>display</code><code>true</code>呈现,但使用<code>&amp;&amp;</code> logical运算符而不是<code>if/else</code>语句。 </section>
<section id='instructions'>
再来看看前面的示例,<code>h1</code>还是在<code>display</code><code>true</code>时被渲染,但使用<code>&&</code>逻辑运算符代替<code>if/else</code>语句。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyComponent</code>应该存在并呈现
- text: <code>MyComponent</code>应该存在并被渲染
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find('MyComponent').length; })());
- text: 当<code>display</code>设置为<code>true</code> ,应该渲染<code>div</code> <code>button</code>和<code>h1</code>
- text: 当<code>display</code>设置为<code>true</code>时,<code>div</code><code>button</code>和<code>h1</code>标签应该被渲染
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: true}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(updated.find(''div'').length === 1 && updated.find(''div'').children().length === 2 && updated.find(''button'').length === 1 && updated.find(''h1'').length === 1); }; '
- text: 当<code>display</code>设置为<code>false</code> ,只应呈现<code>div</code>和<code>button</code>
- text: 当<code>display</code>设置为<code>false</code>,只<code>div</code>和<code>button</code>应该被渲染
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: false}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(updated.find(''div'').length === 1 && updated.find(''div'').children().length === 1 && updated.find(''button'').length === 1 && updated.find(''h1'').length === 0); }; '
- text: render方法应该使用&& logical运算符来检查this.state.display的条件。
- text: render 方法应该使用<code>&&</code>逻辑运算符来检查<code>this.state.display</code>的条件。
testString: getUserInput => assert(getUserInput('index').includes('&&'));
```
@ -46,9 +52,9 @@ class MyComponent extends React.Component {
this.toggleDisplay = this.toggleDisplay.bind(this);
}
toggleDisplay() {
this.setState({
display: !this.state.display
});
this.setState(state => ({
display: !state.display
}));
}
render() {
// change code below this line
@ -60,7 +66,6 @@ class MyComponent extends React.Component {
);
}
};
```
</div>
@ -70,7 +75,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -80,8 +85,31 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
display: true
}
this.toggleDisplay = this.toggleDisplay.bind(this);
}
toggleDisplay() {
this.setState(state => ({
display: !state.display
}));
}
render() {
// change code below this line
return (
<div>
<button onClick={this.toggleDisplay}>Toggle Display</button>
{this.state.display && <h1>Displayed!</h1>}
</div>
);
}
};
```
/section>
</section>

View File

@ -3,34 +3,44 @@ id: 5a24c314108439a4d4036187
title: Use a Ternary Expression for Conditional Rendering
challengeType: 6
isRequired: false
videoUrl: ''
forumTopicId: 301414
localeTitle: 使用三元表达式进行条件渲染
---
## Description
<section id="description">在继续使用动态渲染技术之前最后一种方法是使用内置的JavaScript条件来渲染你想要的东西 <em><strong>三元运算符</strong></em> 。三元运算符通常用作JavaScript中<code>if/else</code>语句的快捷方式。它们不像传统的<code>if/else</code>语句那样健壮但它们在React开发人员中非常受欢迎。这样做的一个原因是因为JSX是如何编译的 <code>if/else</code>语句不能直接插入到JSX代码中。您可能已经注意到这几个挑战 - 当需要<code>if/else</code>语句时,它总是在<code>return</code>语句<em>之外</em> 。如果要在JSX中实现条件逻辑三元表达式可能是一个很好的选择。回想一下三元运算符有三个部分但是你可以将几个三元表达式组合在一起。这是基本语法 <blockquote>条件? expressionIfTrueexpressionIfFalse </blockquote></section>
<section id='description'>
在继续使用动态渲染技术之前,还有最后一种方法可以渲染你想要的东西,它使用内置的 JavaScript 条件:<em><strong>三元运算符</strong></em>。三元运算符经常被用作 JavaScript 中<code>if/else</code>语句的缩写。它们不像传统的<code>if/else</code>语句那样健壮,但是在 React 开发人员中非常流行,原因之一就是 JSX 的编译原理,<code>if/else</code>语句不能直接插入到 JSX 代码中。你可能在前几个挑战就注意到了这一点--当需要<code>if/else</code>语句时,它总是在<code>return</code>语句<em>外面</em>。如果你想在 JSX 中实现条件逻辑,三元表达式是一个很好的选择。回想一下,三元运算符有三个部分,但是你可以将多个三元表达式组合在一起。以下是基本语法:
```js
condition ? expressionIfTrue : expressionIfFalse
```
</section>
## Instructions
<section id="instructions">代码编辑器在<code>CheckUserAge</code>组件的<code>render()</code>方法中定义了三个常量。它们被称为<code>buttonOne</code> <code>buttonTwo</code><code>buttonThree</code> 。每个都分配了一个表示按钮元素的简单JSX表达式。首先使用<code>input</code><code>userAge</code>初始化<code>CheckUserAge</code>的状态, <code>userAge</code>其设置为空字符串的值。一旦组件向页面呈现信息,用户就应该有办法与它进行交互。在组件的<code>return</code>语句中,设置一个实现以下逻辑的三元表达式:当页面首次加载时,将提交按钮<code>buttonOne</code>呈现给页面。然后,当用户输入他们的年龄并单击该按钮时,根据年龄呈现不同的按钮。如果用户输入的数字小于<code>18</code> ,则渲染<code>buttonThree</code> 。如果用户输入的数字大于或等于<code>18</code> ,则渲染<code>buttonTwo</code></section>
<section id='instructions'>
代码编辑器在<code>CheckUserAge</code>组件的<code>render()</code>方法中定义了三个常量,它们分别是<code>buttonOne</code><code>buttonTwo</code><code>buttonThree</code>。每个都分配了一个表示按钮元素的简单 JSX 表达式。首先,使用<code>input</code><code>userAge</code>初始化<code>CheckUserAge</code>的 state并将其值设置为空字符串。
一旦组件将信息渲染给页面,用户应该有一种方法与之交互。在组件的<code>return</code>语句中,设置一个实现以下逻辑的三元表达式:当页面首次加载时,将提交按钮<code>buttonOne</code>渲染到页面。然后,当用户输入年龄并点击该按钮时,根据年龄渲染不同的按钮。如果用户输入的数字小于<code>18</code>,则渲染<code>buttonThree</code>。如果用户输入的数字大于或等于<code>18</code>,则渲染<code>buttonTwo</code>
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>CheckUserAge</code>组件应使用单个<code>input</code>元素和单个<code>button</code>元素进行渲染
- text: <code>CheckUserAge</code>组件应该渲染出单个<code>input</code>元素和单个<code>button</code>元素。
testString: assert(Enzyme.mount(React.createElement(CheckUserAge)).find('div').find('input').length === 1 && Enzyme.mount(React.createElement(CheckUserAge)).find('div').find('button').length === 1);
- text: 应使用<code>userAge</code>属性和<code>input</code>属性初始化<code>CheckUserAge</code>组件的状态,两者都设置为空字符串的值
- text: <code>CheckUserAge</code>组件的 state 应该用<code>userAge</code>属性和<code>input</code>属性初始化,并且这两个属性的值都被设置为空字符串。
testString: assert(Enzyme.mount(React.createElement(CheckUserAge)).state().input === '' && Enzyme.mount(React.createElement(CheckUserAge)).state().userAge === '');
- text: 当<code>CheckUserAge</code>组件首次呈现给DOM时 <code>button</code>内部文本应该是Submit。
- text: 当<code>CheckUserAge</code>组件首次渲染到 DOM 时,<code>按钮</code>内部文本应Submit。
testString: assert(Enzyme.mount(React.createElement(CheckUserAge)).find('button').text() === 'Submit');
- text: 进入一个数小于18 <code>input</code>元件和<code>button</code>被点击, <code>button</code>的内部文本应该<code>You Shall Not Pass</code>
- text: 当小于 18 的数字输入到<code>input</code>元素中并点击该<code>按钮</code>时,该<code>按钮</code>的内部文本应该<code>You Shall Not Pass</code>。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const initialButton = mockedComponent.find(''button'').text(); const enter3AndClickButton = () => { mockedComponent.find(''input'').simulate(''change'', {target: { value: ''3'' }}); mockedComponent.find(''button'').simulate(''click''); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find(''button'').text(); }); }; const enter17AndClickButton = () => { mockedComponent.find(''input'').simulate(''change'', {target: { value: ''17'' }}); mockedComponent.find(''button'').simulate(''click''); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find(''button'').text(); }); }; const userAge3 = await enter3AndClickButton(); const userAge17 = await enter17AndClickButton(); assert(initialButton === ''Submit'' && userAge3 === ''You Shall Not Pass'' && userAge17 === ''You Shall Not Pass''); }; '
- text: 大于或等于18输入到<code>input</code>元件和<code>button</code>被点击, <code>button</code>的内部文本应该阅读<code>You May Enter</code>
- text: 当大于或等于 18 的数字输入到<code>input</code>元素中并点击该<code>按钮</code>时,该<code>按钮</code>的内部文本应该<code>You May Enter</code>。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const initialButton = mockedComponent.find(''button'').text(); const enter18AndClickButton = () => { mockedComponent.find(''input'').simulate(''change'', {target: { value: ''18'' }}); mockedComponent.find(''button'').simulate(''click''); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find(''button'').text(); }); }; const enter35AndClickButton = () => { mockedComponent.find(''input'').simulate(''change'', {target: { value: ''35'' }}); mockedComponent.find(''button'').simulate(''click''); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find(''button'').text(); }); }; const userAge18 = await enter18AndClickButton(); const userAge35 = await enter35AndClickButton(); assert(initialButton === ''Submit'' && userAge18 === ''You May Enter'' && userAge35 === ''You May Enter''); }; '
- text: 一旦提交了一个数字,并再次更改了<code>input</code>的值,该<code>button</code>应返回到<code>Submit</code>
- text: 一旦提交了一个数字,并再次更改了<code>input</code>的值,该<code>按钮</code>内部文本应该变回<code>Submit</code>。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(CheckUserAge)); const enter18AndClickButton = () => { mockedComponent.find(''input'').simulate(''change'', {target: { value: ''18'' }}); mockedComponent.find(''button'').simulate(''click''); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find(''button'').text(); }); }; const changeInputDontClickButton = () => { mockedComponent.find(''input'').simulate(''change'', {target: { value: ''5'' }}); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find(''button'').text(); }); }; const enter10AndClickButton = () => { mockedComponent.find(''input'').simulate(''change'', {target: { value: ''10'' }}); mockedComponent.find(''button'').simulate(''click''); return waitForIt(() => { mockedComponent.update(); return mockedComponent.find(''button'').text(); }); }; const userAge18 = await enter18AndClickButton(); const changeInput1 = await changeInputDontClickButton(); const userAge10 = await enter10AndClickButton(); const changeInput2 = await changeInputDontClickButton(); assert(userAge18 === ''You May Enter'' && changeInput1 === ''Submit'' && userAge10 === ''You Shall Not Pass'' && changeInput2 === ''Submit''); }; '
- text: 的代码不应包含任何<code>if/else</code>语句。
- text: 的代码不应包含任何<code>if/else</code>语句。
testString: assert(new RegExp(/(\s|;)if(\s|\()/).test(Enzyme.mount(React.createElement(CheckUserAge)).instance().render.toString()) === false);
```
@ -43,6 +53,7 @@ tests:
<div id='jsx-seed'>
```jsx
const inputStyle = {
width: 235,
margin: 5
@ -60,13 +71,13 @@ class CheckUserAge extends React.Component {
handleChange(e) {
this.setState({
input: e.target.value,
userAge: "
userAge: ''
});
}
submit() {
this.setState({
userAge: this.state.input
});
this.setState(state => ({
userAge: state.input
}));
}
render() {
const buttonOne = <button onClick={this.submit}>Submit</button>;
@ -87,7 +98,6 @@ class CheckUserAge extends React.Component {
);
}
};
```
</div>
@ -97,7 +107,7 @@ class CheckUserAge extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<CheckUserAge />, document.getElementById('root'))
```
</div>
@ -107,8 +117,57 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const inputStyle = {
width: 235,
margin: 5
}
class CheckUserAge extends React.Component {
constructor(props) {
super(props);
this.state = {
userAge: '',
input: ''
}
this.submit = this.submit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({
input: e.target.value,
userAge: ''
});
}
submit() {
this.setState(state => ({
userAge: state.input
}));
}
render() {
const buttonOne = <button onClick={this.submit}>Submit</button>;
const buttonTwo = <button>You May Enter</button>;
const buttonThree = <button>You Shall Not Pass</button>;
return (
<div>
<h3>Enter Your Age to Continue</h3>
<input
style={inputStyle}
type="number"
value={this.state.input}
onChange={this.handleChange} /><br />
{
this.state.userAge === '' ?
buttonOne :
this.state.userAge >= 18 ?
buttonTwo :
buttonThree
}
</div>
);
}
};
```
/section>
</section>

View File

@ -3,32 +3,37 @@ id: 5a24c314108439a4d4036183
title: Use Advanced JavaScript in React Render Method
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 在React Render方法中使用高级JavaScript
forumTopicId: 301415
localeTitle: 在 React Render 方法中使用 JavaScript
---
## Description
<section id="description">在以前的挑战中,您学习了如何使用大括号<code>{ }</code>将JavaScript代码注入JSX代码以执行诸如访问道具传递道具访问状态在代码中插入注释以及最近为组件设置样式等任务。这些都是将JavaScript放入JSX的常见用例但它们并不是您在React组件中使用JavaScript代码的唯一方法。您也可以在<code>return</code>语句之前直接在<code>render</code>方法中编写JavaScript <strong><em>而不</em></strong>必将其插入花括号中。这是因为它还不在JSX代码中。当你想在<em>里面</em>的JSX代码后使用一个变量<code>return</code>的语句,你把变量名花括号内。 </section>
<section id='description'>
在之前的挑战中,你学习了如何使用大括号<code>{ }</code>将 JavaScript 代码插入到 JSX 代码中,用于访问 props、传递 props、访问 state、在代码中插入注释以及最近学习的定制组件样式等任务。这些都是将 JavaScript 放在 JSX 中的常见用例,但是在 React 组件中使用 JavaScript 代码还有其他方式。
<code>render</code>方法中编写 JavaScript你可以把 JavaScript 直接放在<code>return</code>语句之前,而<strong><em>不必</em></strong>将其插入大括号中。这是因为它还不在 JSX 代码中。当你稍后想在<code>return</code>语句中的 JSX 代码中使用变量时,可以将变量名放在大括号中。
</section>
## Instructions
<section id="instructions">在提供的代码中, <code>render</code>方法有一个数组其中包含20个短语用于表示经典1980年代Magic Eight Ball玩具中的答案。按钮单击事件绑定到<code>ask</code>方法,因此每次单击该按钮时,将生成随机数并将其存储为<code>randomIndex</code>状态。在第52行删除字符串<code>&quot;change me!&quot;</code>并重新分配<code>answer</code> const以便每次组件更新时您的代码随机访问<code>possibleAnswers</code>数组的不同索引。最后,在<code>p</code>标签内插入<code>answer</code> const。 </section>
<section id='instructions'>
在提供的代码中,<code>render</code>方法中有一个包含 20 个短语的数组,用于表示 20 世纪 80 年代经典魔术八球玩具中的答案。绑定<code>ask</code>方法到按钮的单击事件,每次单击该按钮时,将生成随机数并将其存储为 state 中的<code>randomIndex</code>。在第 52 行,删除字符串<code>"change me!"</code>并重新分配<code>answer</code>常量,以便每次组件更新时,你的代码随机访问<code>possibleAnswers</code>数组的不同索引。最后,在<code>p</code>标签内插入<code>answer</code>常量。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MagicEightBall</code>组件应该存在并且应该呈现给页面。
- text: <code>MagicEightBall</code>组件应该存在并被渲染到页面。
testString: assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).find('MagicEightBall').length, 1);
- text: <code>MagicEightBall</code>的第一个子应该是一个<code>input</code>元素。
- text: <code>MagicEightBall</code>的第一个子元素应该是<code>input</code>元素。
testString: assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(0).name(), 'input');
- text: <code>MagicEightBall</code>的第三个子应该是一个<code>button</code>元素。
- text: <code>MagicEightBall</code>的第三个子元素应该是<code>button</code>元素。
testString: assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(2).name(), 'button');
- text: <code>MagicEightBall</code>的状态应的属性初始化<code>userInput</code>属性<code>randomIndex</code>都设置为空字符串的值
- text: <code>MagicEightBall</code>的 state 应该用<code>userInput</code>属性<code>randomIndex</code>属性初始化,并且这两个属性的值都应该是空字符串。
testString: assert(Enzyme.mount(React.createElement(MagicEightBall)).state('randomIndex') === '' && Enzyme.mount(React.createElement(MagicEightBall)).state('userInput') === '');
- text: 当<code>MagicEightBall</code>首次挂载到DOM时它应该返回一个空的<code>p</code>元素。
- text: 当<code>MagicEightBall</code>第一次加载到 DOM时,它应该返回一个空的<code>p</code>元素。
testString: assert(Enzyme.mount(React.createElement(MagicEightBall)).find('p').length === 1 && Enzyme.mount(React.createElement(MagicEightBall)).find('p').text() === '');
- text: 当文本输入到<code>input</code>元素并单击该按钮时, <code>MagicEightBall</code>组件应该返回一个<code>p</code>元素,该元素包含<code>possibleAnswers</code>数组中的随机元素。
- text: 当文本输入到<code>input</code>元素中并点击按钮时,<code>MagicEightBall</code>组件应该返回一个<code>p</code>元素,该元素包含数组<code>possibleAnswers</code>中的随机一个元素。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MagicEightBall)); const simulate = () => { comp.find(''input'').simulate(''change'', { target: { value: ''test?'' }}); comp.find(''button'').simulate(''click''); }; const result = () => comp.find(''p'').text(); const _1 = () => { simulate(); return waitForIt(() => result()) }; const _2 = () => { simulate(); return waitForIt(() => result()) }; const _3 = () => { simulate(); return waitForIt(() => result()) }; const _4 = () => { simulate(); return waitForIt(() => result()) }; const _5 = () => { simulate(); return waitForIt(() => result()) }; const _6 = () => { simulate(); return waitForIt(() => result()) }; const _7 = () => { simulate(); return waitForIt(() => result()) }; const _8 = () => { simulate(); return waitForIt(() => result()) }; const _9 = () => { simulate(); return waitForIt(() => result()) }; const _10 = () => { simulate(); return waitForIt(() => result()) }; const _1_val = await _1(); const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); const _5_val = await _5(); const _6_val = await _6(); const _7_val = await _7(); const _8_val = await _8(); const _9_val = await _9(); const _10_val = await _10(); const actualAnswers = [_1_val, _2_val, _3_val, _4_val, _5_val, _6_val, _7_val, _8_val, _9_val, _10_val]; const hasIndex = actualAnswers.filter((answer, i) => possibleAnswers.indexOf(answer) !== -1); const notAllEqual = new Set(actualAnswers); assert(notAllEqual.size > 1 && hasIndex.length === 10);}'
```
@ -50,8 +55,8 @@ class MagicEightBall extends React.Component {
constructor(props) {
super(props);
this.state = {
userInput: ",
randomIndex: "
userInput: '',
randomIndex: ''
}
this.ask = this.ask.bind(this);
this.handleChange = this.handleChange.bind(this);
@ -60,7 +65,7 @@ class MagicEightBall extends React.Component {
if (this.state.userInput) {
this.setState({
randomIndex: Math.floor(Math.random() * 20),
userInput: "
userInput: ''
});
}
}
@ -113,7 +118,6 @@ class MagicEightBall extends React.Component {
);
}
};
```
</div>
@ -123,7 +127,8 @@ class MagicEightBall extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
var possibleAnswers = [ 'It is certain', 'It is decidedly so', 'Without a doubt', 'Yes, definitely', 'You may rely on it', 'As I see it, yes', 'Outlook good', 'Yes', 'Signs point to yes', 'Reply hazy try again', 'Ask again later', 'Better not tell you now', 'Cannot predict now', 'Concentrate and ask again', 'Don\'t count on it', 'My reply is no', 'My sources say no', 'Outlook not so good','Very doubtful', 'Most likely' ];
ReactDOM.render(<MagicEightBall />, document.getElementById('root'))
```
</div>
@ -133,8 +138,62 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const inputStyle = {
width: 235,
margin: 5
}
class MagicEightBall extends React.Component {
constructor(props) {
super(props);
this.state = {
userInput: '',
randomIndex: ''
}
this.ask = this.ask.bind(this);
this.handleChange = this.handleChange.bind(this);
}
ask() {
if (this.state.userInput) {
this.setState({
randomIndex: Math.floor(Math.random() * 20),
userInput: ''
});
}
}
handleChange(event) {
this.setState({
userInput: event.target.value
});
}
render() {
const possibleAnswers = [
"It is certain", "It is decidedly so", "Without a doubt",
"Yes, definitely", "You may rely on it", "As I see it, yes",
"Outlook good", "Yes", "Signs point to yes", "Reply hazy try again",
"Ask again later", "Better not tell you now", "Cannot predict now",
"Concentrate and ask again", "Don't count on it", "My reply is no",
"My sources say no", "Outlook not so good","Very doubtful", "Most likely"
];
const answer = possibleAnswers[this.state.randomIndex];
return (
<div>
<input
type="text"
value={this.state.userInput}
onChange={this.handleChange}
style={inputStyle} /><br />
<button onClick={this.ask}>Ask the Magic Eight Ball!</button><br />
<h3>Answer:</h3>
<p>
{answer}
</p>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,30 +3,35 @@ id: 5a24c314108439a4d403618c
title: Use Array.filter() to Dynamically Filter an Array
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用Array.filter动态过滤数组
forumTopicId: 301416
localeTitle: 使用 Array.Filter() 动态过滤数组
---
## Description
<section id="description"> <code>map</code>数组方法是一个强大的工具在使用React时经常会使用它。另一种与<code>map</code>相关的方法是<code>filter</code> ,它根据条件过滤数组的内容,然后返回一个新数组。例如,如果您的所有用户都具有<code>online</code>属性(可以设置为<code>true</code><code>false</code> ,则可以通过以下方式仅过滤那些在线用户: <code>let onlineUsers = users.filter(user =&gt; user.online);</code> </section>
<section id='description'>
<code>map</code>数组方法是一个强大的工具,在使用 React 时经常使用。与<code>map</code>相关的另一种方法是<code>filter</code>,它根据条件过滤数组的内容,然后返回一个新数组。例如,如果你有一个 users 数组,每个数组元素都有一个可以设置为<code>true</code><code>false</code><code>online</code>属性,你可以只过滤那些在线的用户:
<code>let onlineUsers = users.filter(user => user.online);</code>
</section>
## Instructions
<section id="instructions">在代码编辑器中, <code>MyComponent</code><code>state</code>是用一组用户初始化的。有些用户在线,有些则没有。过滤数组,以便只查看在线用户。要执行此操作,请首先使用<code>filter</code>返回仅包含<code>online</code>属性为<code>true</code>的用户的新数组。然后,在<code>renderOnline</code>变量中,映射已过滤的数组,并为包含其<code>username</code>文本的每个用户返回<code>li</code>元素。确保包括一个独特的<code>key</code> ,就像在最后的挑战中一样。 </section>
<section id='instructions'>
在代码编辑器中,<code>MyComponent</code><code>state</code>由一个 users 数组初始化。有些用户在线,有些则不在线。过滤数组,以便你只看到在线用户。为此,首先使用<code>filter</code>返回一个新数组,该数组只包含<code>online</code>属性为<code>true</code>的用户。然后,在<code>renderOnline</code>变量中,映射经过过滤的数组,并为每个用户返回一个包含它们<code>username</code>文本的<code>li</code>元素。确保像上一个挑战一样包含一个独特的<code>key</code>
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyComponent</code>应该存在并呈现给页面。
- text: <code>MyComponent</code>应该存在并被渲染到页面。
testString: assert.strictEqual(Enzyme.mount(React.createElement(MyComponent)).find('MyComponent').length, 1);
- text: <code>MyComponent</code>的状态应初始化为六个用户的数组。“)
- text: <code>MyComponent</code>的 state 应该初始化为包含 6 个用户的数组。
testString: assert(Array.isArray(Enzyme.mount(React.createElement(MyComponent)).state('users')) === true && Enzyme.mount(React.createElement(MyComponent)).state('users').length === 6);
- text: <code>MyComponent</code>应该返回一个<code>div</code> 一个<code>h1</code> ,然后是一个无序列表,其中包含每个在线状态设置为<code>true</code>用户的<code>li</code>元素
- text: <code>MyComponent</code>应该返回一个<code>div</code>一个<code>h1</code>和一个包含<code>li</code>元素的无序列表,该列表用于展示在线状态为<code>true</code>的每个用户。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MyComponent)); const users = (bool) => ({users:[ { username: ''Jeff'', online: bool }, { username: ''Alan'', online: bool }, { username: ''Mary'', online: bool }, { username: ''Jim'', online: bool }, { username: ''Laura'', online: bool } ]}); const result = () => comp.find(''li'').length; const _1 = result(); const _2 = () => { comp.setState(users(true)); return waitForIt(() => result()) }; const _3 = () => { comp.setState(users(false)); return waitForIt(() => result()) }; const _4 = () => { comp.setState({ users: [] }); return waitForIt(() => result()) }; const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); assert(comp.find(''div'').length === 1 && comp.find(''h1'').length === 1 && comp.find(''ul'').length === 1 && _1 === 4 && _2_val === 5 && _3_val === 0 && _4_val === 0); }; '
- text: <code>MyComponent</code>应该呈现包含每个在线用户用户名的<code>li</code>元素。
- text: <code>MyComponent</code>应该渲染包含每个在线用户用户名的<code>li</code>元素。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MyComponent)); const users = (bool) => ({users:[ { username: ''Jeff'', online: bool }, { username: ''Alan'', online: bool }, { username: ''Mary'', online: bool }, { username: ''Jim'', online: bool }, { username: ''Laura'', online: bool } ]}); const ul = () => { comp.setState(users(true)); return waitForIt(() => comp.find(''ul'').html()) }; const html = await ul(); assert(html === ''<ul><li>Jeff</li><li>Alan</li><li>Mary</li><li>Jim</li><li>Laura</li></ul>''); }; '
- text: 每个列表项元素都应具有唯一的<code>key</code>属性。
- text: 每个列表项元素都应该有一个唯一的<code>key</code>属性。
testString: assert((() => { const ul = Enzyme.mount(React.createElement(MyComponent)).find('ul'); console.log(ul.debug()); const keys = new Set([ ul.childAt(0).key(), ul.childAt(1).key(), ul.childAt(2).key(), ul.childAt(3).key() ]); return keys.size === 4; })());
```
@ -84,7 +89,6 @@ class MyComponent extends React.Component {
);
}
};
```
</div>
@ -94,7 +98,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -104,8 +108,59 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
users: [
{
username: 'Jeff',
online: true
},
{
username: 'Alan',
online: false
},
{
username: 'Mary',
online: true
},
{
username: 'Jim',
online: false
},
{
username: 'Sara',
online: true
},
{
username: 'Laura',
online: true
}
]
}
}
render() {
const usersOnline = this.state.users.filter(user => {
return user.online;
});
const renderOnlineUsers = usersOnline.map(user => {
return (
<li key={user.username}>{user.username}</li>
);
});
return (
<div>
<h1>Current Online Users:</h1>
<ul>
{renderOnlineUsers}
</ul>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,33 +3,42 @@ id: 5a24c314108439a4d403618a
title: Use Array.map() to Dynamically Render Elements
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用Array.map动态渲染元素
forumTopicId: 301417
localeTitle: 使用 Array.map() 动态渲染元素
---
## Description
<section id="description">条件渲染很有用但您可能需要组件渲染未知数量的元素。通常在反应式编程中程序员无法知道应用程序的状态直到运行时因为这很大程度上取决于用户与该程序的交互。程序员需要编写代码以提前正确处理未知状态。在React中使用<code>Array.map()</code>说明了这个概念。例如,您创建一个简单的“待办事项列表”应用程序。作为程序员,您无法知道用户可能在其列表中有多少项。您需要设置组件,以便在使用该程序的人决定今天是洗衣日之前<em><strong>动态呈现</strong></em>正确数量的列表元素。 </section>
<section id='description'>
条件渲染很有用,但是你可能需要组件来渲染未知数量的元素。通常在响应式编程中,程序员在应用程序运行时之前无法知道其 state因为这在很大程度上取决于用户与该程序的交互。程序员需要提前编写代码来正确处理未知状态。在 React 中使用<code>Array.map()</code>阐明了这个概念。
例如你创建一个简单的“To Do List”应用程序。作为程序员你无法知道用户可能在其列表中有多少项。你需要设置组件以便在使用该程序的人决定今天今日待办事项之前<em><strong>动态渲染</strong></em>正确数量的列表元素。
</section>
## Instructions
<section id="instructions">代码编辑器设置了大部分<code>MyToDoList</code>组件。如果您完成了受控制的表单质询,那么这些代您会注意到一个<code>textarea</code>和一个<code>button</code> ,以及一些跟踪其状态的方法,但是还没有任何内容呈现给页面。在<code>constructor</code>内部,创建一个<code>this.state</code>对象并定义两个状态: <code>userInput</code>应初始化为空字符串, <code>toDoList</code>应初始化为空数组。接下来,删除<code>items</code>变量旁边的<code>render()</code>方法中的注释。取而代之,映射存储在组件内部状态中的<code>toDoList</code>数组,并为每个项目动态呈现<code>li</code> 。尝试输入字符串<code>eat, code, sleep, repeat</code><code>textarea</code> ,然后单击按钮,看看会发生什么。 <strong>注意:</strong>您可能知道由这样的映射操作创建的所有兄弟子元素都需要提供唯一的<code>key</code>属性。别担心,这是下一个挑战的主题。 </section>
<section id='instructions'>
代码编辑器完成了<code>MyToDoList</code>组件的大部分设置。如果你完成了受控表单挑战,这些代码中的一些应该看起来很熟悉。你会注意到一个<code>textarea</code>和一个<code>button</code>,以及一些跟踪它们状态的方法,但是页面当前还没有任何东西被渲染。
<code>constructor</code>中,创建一个<code>this.state</code>对象并定义两个 state<code>userInput</code>应该初始化为空字符串,<code>toDoList</code>应该初始化为空数组。接下来,删除<code>items</code>变量旁边<code>render()</code>方法中的注释。取而代之的是,将存储在组件内部 state 中的<code>toDoList</code>数组一一映射并相应的动态呈现<code>li</code>元素。尝试在<code>textarea</code>中输入<code>eat, code, sleep, repeat</code>,然后点击按钮,看看会发生什么。
<strong>注意:</strong>&nbsp;你可能知道,像这样的映射操作创建的所有兄弟子元素都需要提供唯一的<code>key</code>属性。别担心,这是下一个挑战的主题。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: MyToDoList组件应该存在并呈现给页面。
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); return mockedComponent.find("MyToDoList").length === 1; })(), "The MyToDoList component should exist and render to the page.");'
- text: <code>MyToDoList</code>的第一个子<code>MyToDoList</code>应该是<code>textarea</code>元素。
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); return mockedComponent.find("MyToDoList").children().childAt(0).type() === "textarea"; })(), "The first child of <code>MyToDoList</code> should be a <code>textarea</code> element.");'
- text: <code>MyToDoList</code>的第个子<code>MyToDoList</code>应该是一个<code>button</code>元素。
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); return mockedComponent.find("MyToDoList").children().childAt(2).type() === "button"; })(), "The third child of <code>MyToDoList</code> should be a <code>button</code> element.");'
- text: 应使用<code>toDoList</code>将<code>MyToDoList</code>的状态初始化为空数组
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); const initialState = mockedComponent.state(); return Array.isArray(initialState.toDoList) === true && initialState.toDoList.length === 0; })(), "The state of <code>MyToDoList</code> should be initialized with <code>toDoList</code> as an empty array.");'
- text: 应使用<code>userInput</code>将<code>MyToDoList</code>的状态初始化为空字符串
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); const initialState = mockedComponent.state(); return typeof initialState.userInput === "string" && initialState.userInput.length === 0; })(), "The state of <code>MyToDoList</code> should be initialized with <code>userInput</code> as an empty string.");'
- text: 单击“ <code>Create List</code>按钮时, <code>MyToDoList</code>组件应动态返回无序列表,该列表包含输入到<code>textarea</code>元素中的逗号分隔列表的每个项目的列表项元素
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); const simulateChange = (el, value) => el.simulate("change", {target: {value}}); const state_1 = () => { return waitForIt(() => mockedComponent.find("ul").find("li"))}; const setInput = () => { return waitForIt(() => simulateChange(mockedComponent.find("textarea"), "testA, testB, testC"))}; const click = () => { return waitForIt(() => mockedComponent.find("button").simulate("click"))}; const state_2 = () => { return waitForIt(() => { const nodes = mockedComponent.find("ul").find("li"); return { nodes, text: nodes.reduce((t, n) => t + n.text(), "") }; })}; const setInput_2 = () => { return waitForIt(() => simulateChange(mockedComponent.find("textarea"), "t1, t2, t3, t4, t5, t6"))}; const click_1 = () => { return waitForIt(() => mockedComponent.find("button").simulate("click"))}; const state_3 = () => { return waitForIt(() => { const nodes = mockedComponent.find("ul").find("li"); return { nodes, text: nodes.reduce((t, n) => t + n.text(), "") }; })}; const awaited_state_1 = await state_1(); const awaited_setInput = await setInput(); const awaited_click = await click(); const awaited_state_2 = await state_2(); const awaited_setInput_2 = await setInput_2(); const awaited_click_1 = await click_1(); const awaited_state_3 = await state_3(); assert(awaited_state_1.length === 0 && awaited_state_2.nodes.length === 3 && awaited_state_3.nodes.length === 6 && awaited_state_2.text === "testA testB testC" && awaited_state_3.text === "t1 t2 t3 t4 t5 t6", "When the <code>Create List</code> button is clicked, the <code>MyToDoList</code> component should dynamically return an unordered list that contains a list item element for every item of a comma-separated list entered into the <code>textarea</code> element."); }; '
- text: <code>MyToDoList</code>组件应该存在并渲染到页面。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); return mockedComponent.find('MyToDoList').length === 1; })());
- text: <code>MyToDoList</code>组件的第一个子元素应该是<code>textarea</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); return mockedComponent.find('MyToDoList').children().childAt(0).type() === 'textarea'; })());
- text: <code>MyToDoList</code>组件的第个子元素应该是<code>br</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); return mockedComponent.find('MyToDoList').children().childAt(1).type() === 'br'; })());
- text: <code>MyToDoList</code>组件的第三个子元素应该是<code>button</code>元素
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); return mockedComponent.find('MyToDoList').children().childAt(2).type() === 'button'; })());
- text: <code>MyToDoList</code>的 state 应该使用被设置为空数组的<code>toDoList</code>进行初始化
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); const initialState = mockedComponent.state(); return Array.isArray(initialState.toDoList) === true && initialState.toDoList.length === 0; })());
- text: <code>MyToDoList</code>的 state 应该使用被设置为空字符串的<code>userInput</code>进行初始化
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); const initialState = mockedComponent.state(); return typeof initialState.userInput === 'string' && initialState.userInput.length === 0; })());
- text: 单击<code>Create List</code>按钮时,<code>MyToDoList</code>组件应该动态返回一个无序列表,该列表包含输入到<code>textarea</code>元素中的逗号分隔列表的每个项目的列表项目元素。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); const simulateChange = (el, value) => el.simulate(''change'', {target: {value}}); const state_1 = () => { return waitForIt(() => mockedComponent.find(''ul'').find(''li''))}; const setInput = () => { return waitForIt(() => simulateChange(mockedComponent.find(''textarea''), "testA, testB, testC"))}; const click = () => { return waitForIt(() => mockedComponent.find(''button'').simulate(''click''))}; const state_2 = () => { return waitForIt(() => { const nodes = mockedComponent.find(''ul'').find(''li''); return { nodes, text: nodes.reduce((t, n) => t + n.text(), '''') }; })}; const setInput_2 = () => { return waitForIt(() => simulateChange(mockedComponent.find(''textarea''), "t1, t2, t3, t4, t5, t6"))}; const click_1 = () => { return waitForIt(() => mockedComponent.find(''button'').simulate(''click''))}; const state_3 = () => { return waitForIt(() => { const nodes = mockedComponent.find(''ul'').find(''li''); return { nodes, text: nodes.reduce((t, n) => t + n.text(), '''') }; })}; const awaited_state_1 = await state_1(); const awaited_setInput = await setInput(); const awaited_click = await click(); const awaited_state_2 = await state_2(); const awaited_setInput_2 = await setInput_2(); const awaited_click_1 = await click_1(); const awaited_state_3 = await state_3(); assert(awaited_state_1.length === 0 && awaited_state_2.nodes.length === 3 && awaited_state_3.nodes.length === 6 && awaited_state_2.text === ''testA testB testC'' && awaited_state_3.text === ''t1 t2 t3 t4 t5 t6''); }; '
```
@ -68,6 +77,73 @@ class MyToDoList extends React.Component {
}
render() {
const items = null; // change code here
return (
<div>
<textarea
onChange={this.handleChange}
value={this.state.userInput}
style={textAreaStyles}
placeholder="Separate Items With Commas" />
<br />
<button onClick={this.handleSubmit}>Create List</button>
<h1>My "To Do" List:</h1>
<ul>
{items}
</ul>
</div>
);
}
};
```
</div>
### After Test
<div id='jsx-teardown'>
```js
ReactDOM.render(<MyToDoList />, document.getElementById('root'))
```
</div>
</section>
## Solution
<section id='solution'>
```js
const textAreaStyles = {
width: 235,
margin: 5
};
class MyToDoList extends React.Component {
constructor(props) {
super(props);
this.state = {
toDoList: [],
userInput: ''
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleSubmit() {
const itemsArray = this.state.userInput.split(',');
this.setState({
toDoList: itemsArray
});
}
handleChange(e) {
this.setState({
userInput: e.target.value
});
}
render() {
const items = this.state.toDoList.map( (item, i) => {
return <li key={i}>{item}</li>
});
return (
<div>
<textarea
@ -84,28 +160,6 @@ class MyToDoList extends React.Component {
);
}
};
```
</div>
### After Test
<div id='jsx-teardown'>
```js
console.info('after the test');
```
</div>
</section>
## Solution
<section id='solution'>
```js
// solution required
```
/section>

View File

@ -3,24 +3,28 @@ id: 5a24c314108439a4d403616b
title: Use Default Props
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用默认道具
forumTopicId: 301418
localeTitle: 使用默认的 Props
---
## Description
<section id="description"> React还有一个设置默认道具的选项。您可以将默认道具分配给组件作为组件本身的属性如果需要React会分配默认支柱。如果没有显式提供值这允许您指定prop值应该是什么。例如如果您声明<code>MyComponent.defaultProps = { location: &#39;San Francisco&#39; }</code> ,则您已定义了设置为<code>San Francisco</code>字符串的位置道具除非您另行指定。如果道具未定义则React会指定默认道具但如果您将<code>null</code>作为道具的值传递,则它将保持为<code>null</code></section>
<section id='description'>
React 还有一个设置默认 props 的选项。你可以将默认 props 作为组件本身的属性分配给组件React 会在必要时分配默认 prop。如果没有显式的提供任何值这允许你指定 prop 值应该是什么。例如,如果你声明<code>MyComponent.defaultProps = { location: 'San Francisco' }</code>,即定义一个 location 属性,并且其值在没有另行制定的情况下被设置为字符串<code>San Francisco</code>。如果 props 未定义,则 React 会分配默认 props但如果你将<code>null</code>作为 prop 的值,它将保持<code>null</code>
</section>
## Instructions
<section id="instructions">代码编辑器显示<code>ShoppingCart</code>组件。在此组件上定义默认道具,指定值为<code>0</code>的道具<code>items</code></section>
<section id='instructions'>
代码编辑器中有一个<code>ShoppingCart</code>组件。在这个组件上定义默认 props它指定一个<code>items</code>prop其值为<code>0</code>
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>ShoppingCart</code>组件应该呈现
- text: 应该渲染<code>ShoppingCart</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart)); return mockedComponent.find('ShoppingCart').length === 1; })());
- text: '<code>ShoppingCart</code>组件应具有<code>{ items: 0 }</code>的默认支柱。'
- text: '<code>ShoppingCart</code>组件应该有一个<code>{ items: 0 }</code>的默认 prop。'
testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart)); mockedComponent.setProps({items: undefined}); return mockedComponent.find(''ShoppingCart'').props().items === 0; })());'
```
@ -51,7 +55,7 @@ const ShoppingCart = (props) => {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<ShoppingCart />, document.getElementById('root'))
```
</div>
@ -61,8 +65,20 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const ShoppingCart = (props) => {
return (
<div>
<h1>Shopping Cart Component</h1>
</div>
)
};
// change code below this line
ShoppingCart.defaultProps = {
items: 0
}
```
/section>
</section>

View File

@ -3,26 +3,37 @@ id: 5a24c314108439a4d403616d
title: Use PropTypes to Define the Props You Expect
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用PropTypes定义期望的道具
forumTopicId: 301419
localeTitle: 使用 PropTypes定义期望的 Props
---
## Description
<section id="description"> React提供了有用的类型检查功能以验证组件是否接收到正确类型的道具。例如您的应用程序进行API调用以检索您希望在数组中的数据然后将其作为prop传递给组件。您可以在组件上设置<code>propTypes</code> ,以要求数据类型为<code>array</code> 。当数据是任何其他类型时,这将抛出有用的警告。当您提前知道道具类型时,设置<code>propTypes</code>被认为是最佳做法。您可以使用与定义<code>defaultProps</code>相同的方式为组件定义<code>propTypes</code>属性。这样做将检查给定键的道具是否存在给定类型。这是一个需要类型<code>function</code>的例子,名为<code>handleClick</code> <code>MyComponent.propTypes = { handleClick: PropTypes.func.isRequired }</code>在上面的例子中, <code>PropTypes.func</code>部分检查<code>handleClick</code>是一个函数。添加<code>isRequired</code>告诉React <code>handleClick</code>是该组件的必需属性。如果未提供支柱,您将看到警告。还要注意<code>func</code>代表<code>function</code> 。在七种JavaScript原语类型中 <code>function</code><code>boolean</code> (写为<code>bool</code> 是唯一使用异常拼写的两种类型。除了原始类型还有其他类型可用。例如您可以检查prop是否为React元素。有关所有选项请参阅文档。 <strong>注意:</strong>从React v15.5.0开始, <code>PropTypes</code>独立于React <code>import PropTypes from &#39;prop-types&#39;;</code> ,如下所示: <code>import PropTypes from &#39;prop-types&#39;;</code> </section>
<section id='description'>
React 提供了有用的类型检查特性,以验证组件是否接收了正确类型的 props。例如你的应用程序调用 API 来检索你希望在数组中的数据,然后将数据作为 prop 传递给组件。你可以在组件上设置<code>propTypes</code>,以要求数据的类型为<code>array</code>。当数据是任何其他类型时,都会抛出警告。
当你提前知道 prop 的类型时,最好的做法是设置<code>propTypes</code>。可以为组件定义<code>propTypes</code>属性,方法与定义<code>defaultProps</code>相同。这样做将检查给定键的 prop 是否是给定类型。这里有一个示例,名为<code>handleClick</code>的 prop 应为<code>function</code>类型:
<code>MyComponent.propTypes = { handleClick: PropTypes.func.isRequired }</code>
在上面的示例中,<code>PropTypes.func</code>部分检查<code>handleClick</code>是否为函数。添加<code>isRequired</code>是为了告诉 React<code>handleClick</code>是该组件的必需属性。如果未提供该 prop你将看到警告信息。另请注意<code>func</code>表示<code>function</code>。在 7 种 JavaScript 基本类型中,<code>function</code><code>boolean</code>(写为<code>bool</code>)是仅有的使用异常拼写的两种类型。除了基本类型,还有其他类型可用。例如,你可以检查 prop 是否为 React 组件,请参阅文档以获取所有选项。
<strong>注意:</strong>在 React v15.5.0 版本中, <code>PropTypes</code>可以从 React 中单独引入,如下所示:
<code>import React, { PropTypes } from 'react';</code>
</section>
## Instructions
<section id="instructions"><code>Items</code>组件定义<code>propTypes</code>以要求<code>quantity</code>作为prop并验证它是否为<code>number</code>类型。 </section>
<section id='instructions'>
<code>Items</code>组件定义<code>propTypes</code>,要求<code>quantity</code>作为 prop并验证它是<code>number</code>类型。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>ShoppingCart</code>组件应该呈现
- text: 应该渲染<code>ShoppingCart</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart)); return mockedComponent.find('ShoppingCart').length === 1; })());
- text: <code>Items</code>组件应该呈现
- text: 应该渲染<code>Items</code>组件。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart)); return mockedComponent.find('Items').length === 1; })());
- text: <code>Items</code>组件应包含<code>propTypes</code>检查,该检查要求<code>quantity</code><code>number</code>
- text: <code>Items</code>组件应包含一个<code>propTypes</code>,以检查<code>quantity</code><code>number</code>类型
testString: getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/ /g, ''); return noWhiteSpace.includes('quantity:PropTypes.number.isRequired') && noWhiteSpace.includes('Items.propTypes='); })());
```
@ -55,7 +66,6 @@ class ShoppingCart extends React.Component {
return <Items />
}
};
```
</div>
@ -76,7 +86,7 @@ var PropTypes = {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<ShoppingCart />, document.getElementById('root'))
```
</div>
@ -86,8 +96,30 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const Items = (props) => {
return <h1>Current Quantity of Items in Cart: {props.quantity}</h1>
};
// change code below this line
Items.propTypes = {
quantity: PropTypes.number.isRequired
};
// change code above this line
Items.defaultProps = {
quantity: 0
};
class ShoppingCart extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Items />
}
};
```
/section>
</section>

View File

@ -3,28 +3,33 @@ id: 5a24c314108439a4d4036165
title: Use React to Render Nested Components
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用React渲染嵌套组件
forumTopicId: 301420
localeTitle: 使用 React 渲染嵌套组件
---
## Description
<section id="description">最后一个挑战显示了组合两个组件的简单方法但是有许多不同的方法可以使用React组合组件。组件组合是React强大的功能之一。当您使用React时重要的是开始根据组件如上一个挑战中的App示例考虑您的用户界面。您将UI分解为其基本构建块这些块成为组件。这有助于将负责UI的代码与负责处理应用程序逻辑的代码分开。它可以大大简化复杂项目的开发和维护。 </section>
<section id='description'>
上一个挑战显示了组合两个组件的简单方法,但是有许多不同的方法可以把 React 组件组合在一起。
组件组合是 React 的强大功能之一。当你使用 React 时,应当先用组件的思路考虑清楚用户界面的结构(如上一个挑战中的 App 示例)。可以将 UI 分解为基本的构建块,这些构建块就是组件。这样做有助于将负责 UI 的代码与负责处理应用程序逻辑的代码分开,并可以大大简化复杂项目的开发和维护。
</section>
## Instructions
<section id="instructions">代码编辑器中定义了两个功能组件,名为<code>TypesOfFruit</code><code>Fruits</code> 。取<code>TypesOfFruit</code>组分和构成它,或者它<em></em> ,所述内<code>Fruits</code>组分。然后使用<code>Fruits</code>组件并将其嵌套在<code>TypesOfFood</code>组件中。结果应该是一个嵌套在父组件中的子组件,它嵌套在它自己的父组件中! </section>
<section id='instructions'>
代码编辑器中定义了两个功能组件,分别是<code>TypesOfFruit</code><code>Fruits</code>。请把<code>TypesOfFruit</code>组件放到<code>Fruits</code>组件中,然后把<code>Fruits</code>组件放到<code>TypesOfFood</code>组件中。结果应该是子组件嵌套在父组件中,父组件嵌套在它本身的父组件中!
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>TypesOfFood</code>组件应返回单个<code>div</code>元素。
- text: <code>TypesOfFood</code>组件应返回单个<code>div</code>元素。
testString: assert(Enzyme.shallow(React.createElement(TypesOfFood)).type() === 'div');
- text: <code>TypesOfFood</code>组件应返回<code>Fruits</code>组件。
- text: <code>TypesOfFood</code>组件应返回<code>Fruits</code>组件。
testString: assert(Enzyme.shallow(React.createElement(TypesOfFood)).props().children[1].type.name === 'Fruits');
- text: <code>Fruits</code>组件应返回<code>TypesOfFruit</code>组件。
- text: <code>Fruits</code>组件应返回<code>TypesOfFruit</code>组件。
testString: assert(Enzyme.mount(React.createElement(TypesOfFood)).find('h2').html() === '<h2>Fruits:</h2>');
- text: <code>TypesOfFruit</code>组件应返回<code>h2</code>和<code>ul</code>元素。
- text: <code>TypesOfFruit</code>组件应返回<code>h2</code>和<code>ul</code>元素。
testString: assert(Enzyme.mount(React.createElement(TypesOfFood)).find('ul').text() === 'ApplesBlueberriesStrawberriesBananas');
```
@ -77,7 +82,6 @@ class TypesOfFood extends React.Component {
);
}
};
```
</div>
@ -87,7 +91,7 @@ class TypesOfFood extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<TypesOfFood />, document.getElementById('root'))
```
</div>
@ -97,8 +101,48 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
const TypesOfFruit = () => {
return (
<div>
<h2>Fruits:</h2>
<ul>
<li>Apples</li>
<li>Blueberries</li>
<li>Strawberries</li>
<li>Bananas</li>
</ul>
</div>
);
};
const Fruits = () => {
return (
<div>
{ /* change code below this line */ }
<TypesOfFruit />
{ /* 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 */ }
</div>
);
}
};
```
/section>
</section>

View File

@ -3,27 +3,62 @@ id: 5a24c314108439a4d4036176
title: Use State to Toggle an Element
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用State切换元素
forumTopicId: 301421
localeTitle: 使用 State 切换元素
---
## Description
<section id="description">您可以以比您目前所见的更复杂的方式在React应用程序中使用<code>state</code> 。一个示例是监视值的状态然后根据此值有条件地呈现UI。有几种不同的方法可以实现这一点代码编辑器显示了一种方法。 </section>
<section id='description'>
有时可能在更新状态的时候想知道上一个状态是什么。但是状态更新是异步的,这意味着 React 可能会把多个 <code>setState()</code> 集中在一起批量更新。所以设置 <code>this.state</code> 或者 <code>this.props</code> 后值没有立即更新。所以最好不要写如下的代码:
```js
this.setState({
counter: this.state.counter + this.props.increment
});
```
正确的做法是,给 <code>setState</code> 传入一个函数,这个函数可以访问 state 和 props。给 <code>setState</code> 传入函数可以返回赋值后的 state 和 props。代码可以重写为这样
```js
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
如果只需要 `state`,那么用下面的格式也是可以的:
```js
this.setState(state => ({
counter: state.counter + 1
}));
```
注意一定要把 object 放在括号里,否则 JavaScript 会认为这只是代码片段。
</section>
## Instructions
<section id="instructions"> <code>MyComponent</code>有一个<code>visibility</code>属性,初始化为<code>false</code> 。如果<code>visibility</code>值为true则render方法返回一个视图;如果为false则返回不同的视图。目前无法更新组件<code>state</code><code>visibility</code>属性。该值应在true和false之间来回切换。按钮上有一个单击处理程序它触发一个名为<code>toggleVisibility()</code>的类方法。定义此方法,以便在调用方法时, <code>visibility</code> <code>state</code>切换为相反的值。如果<code>visibility</code><code>false</code> ,该方法将其设置为<code>true</code> ,反之亦然。最后,单击按钮以根据其<code>state</code>查看组件的条件呈现。 <strong>提示:</strong>不要忘记将<code>this</code>关键字绑定到构造函数中的方法! </section>
<section id='instructions'>
<code>MyComponent</code>有一个初始值为<code>false</code><code>visibility</code>属性。如果<code>visibility</code>的值为 truerender 方法返回一个视图,如果为 false返回另一个视图。
目前,无法更新组件的<code>state</code>中的<code>visibility</code>属性,该值应在 true 和 false 之间来回切换。按钮上有一个单击处理程序,它触发一个名为<code>toggleVisibility()</code>的类方法。定义此方法,以便<code>visibility</code><code>state</code>在调用方法时切换到相反的值。如果<code>visibility</code><code>false</code>,则该方法将其设置为<code>true</code>,反之亦然。
最后,单击按钮以查看基于其<code>state</code>的组件的条件渲染。
<strong>提示:</strong>&nbsp;不要忘记将<code>this</code>关键字绑定到构造函数中的方法上!
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyComponent</code>应该返回一个包含<code>button</code>的<code>div</code>元素。
testString: 'assert.strictEqual(Enzyme.mount(React.createElement(MyComponent)).find("div").find("button").length, 1, "<code>MyComponent</code> should return a <code>div</code> element which contains a <code>button</code>.");'
- text: <code>MyComponent</code>的状态应该初始化,并将<code>visibility</code>属性设置为<code>false</code>
testString: 'assert.strictEqual(Enzyme.mount(React.createElement(MyComponent)).state("visibility"), false, "The state of <code>MyComponent</code> should initialize with a <code>visibility</code> property set to <code>false</code>.");'
- text: 单击按钮元素应在<code>true</code>和<code>false</code>之间切换状态的<code>visibility</code>属性。
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ visibility: false }); return waitForIt(() => mockedComponent.state("visibility")); }; const second = () => { mockedComponent.find("button").simulate("click"); return waitForIt(() => mockedComponent.state("visibility")); }; const third = () => { mockedComponent.find("button").simulate("click"); return waitForIt(() => mockedComponent.state("visibility")); }; const firstValue = await first(); const secondValue = await second(); const thirdValue = await third(); assert(!firstValue && secondValue && !thirdValue, "Clicking the button element should toggle the <code>visibility</code> property in state between <code>true</code> and <code>false</code>."); }; '
- text: <code>MyComponent</code>应该返回一个<code>div</code>元素,其中包含一个<code>button</code>元素。
testString: assert.strictEqual(Enzyme.mount(React.createElement(MyComponent)).find('div').find('button').length, 1);
- text: <code>MyComponent</code>应该使用设置为<code>false</code><code>visibility</code>属性来初始化其 state
testString: assert.strictEqual(Enzyme.mount(React.createElement(MyComponent)).state('visibility'), false);
- text: 单击按钮元素应在<code>true</code>和<code>false</code>之间切换<code>visibility</code>属性的状态
testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ visibility: false }); return waitForIt(() => mockedComponent.state(''visibility'')); }; const second = () => { mockedComponent.find(''button'').simulate(''click''); return waitForIt(() => mockedComponent.state(''visibility'')); }; const third = () => { mockedComponent.find(''button'').simulate(''click''); return waitForIt(() => mockedComponent.state(''visibility'')); }; const firstValue = await first(); const secondValue = await second(); const thirdValue = await third(); assert(!firstValue && secondValue && !thirdValue); }; '
- text: 应该传入<code>setState</code> 一个匿名函数。
testString: const paramRegex = '[a-zA-Z$_]\\w*(,[a-zA-Z$_]\\w*)?'; const noSpaces = code.replace(/\s/g, ''); assert(new RegExp('this\\.setState\\((function\\(' + paramRegex + '\\){|([a-zA-Z$_]\\w*|\\(' + paramRegex + '\\))=>)').test(noSpaces));
- text: 不要在 <code>setState</code> 里面使用 <code>this</code>。
testString: assert(!/this\.setState\([^}]*this/.test(code));
```
@ -65,7 +100,6 @@ class MyComponent extends React.Component {
}
}
};
```
</div>
@ -75,7 +109,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -85,8 +119,38 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
visibility: false
};
this.toggleVisibility = this.toggleVisibility.bind(this);
}
toggleVisibility() {
this.setState(state => ({
visibility: !state.visibility
}));
}
render() {
if (this.state.visibility) {
return (
<div>
<button onClick = {this.toggleVisibility}>Click Me</button>
<h1>Now you see me!</h1>
</div>
);
} else {
return (
<div>
<button onClick = {this.toggleVisibility}>Click Me</button>
</div>
);
}
}
};
```
/section>
</section>

View File

@ -3,26 +3,31 @@ id: 5a24c314108439a4d403617d
title: Use the Lifecycle Method componentDidMount
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用生命周期方法componentDidMount
forumTopicId: 301422
localeTitle: 使用生命周期方法componentDidMount
---
## Description
<section id="description">大多数Web开发人员在某些时候需要调用API端点来检索数据。如果您正在使用React那么知道执行此操作的位置非常重要。 React的最佳实践是在生命周期方法<code>componentDidMount()</code>中对服务器进行API调用或任何调用。将组件安装到DOM后调用此方法。此处对<code>setState()</code>任何调用都将触发组件的重新呈现。在此方法中调用API并使用API返回的数据设置状态时一旦收到数据它将自动触发更新。 </section>
<section id='description'>
某些时候,大多数 web 开发人员需要调用 API 端点来检索数据。如果你正在使用 React知道在哪里执行这个动作是很重要的。
React 的最佳实践是在生命周期方法<code>componentDidMount()</code>中对服务器进行 API 调用或任何其他调用。将组件装载到 DOM 后会调用此方法。此处对<code>setState()</code>的任何调用都将触发组件的重新渲染。在此方法中调用 API 并使用 API 返回的数据设置 state 时,一旦收到数据,它将自动触发更新。
</section>
## Instructions
<section id="instructions"> <code>componentDidMount()</code>有一个模拟API调用。它在2.5秒后设置状态以模拟调用服务器以检索数据。此示例请求站点的当前活动用户总数。在render方法中<code>h1</code>呈现<code>activeUsers</code>的值。观看预览中发生的事情,并随时更改超时以查看不同的效果。 </section>
<section id='instructions'>
<code>componentDidMount()</code>中有一个模拟 API 调用。它在 2.5 秒后设置 state以模拟调用服务器检索数据。本示例请求站点的当前活动用户总数。在 render 方法中,把<code>activeUsers</code>渲染到<code>h1</code>标签中。观看预览中发生的事情,随意更改超时时间以查看不同的效果。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyComponent</code>应该呈现一个包含<code>h1</code>标的<code>div</code>元素。
- text: <code>MyComponent</code>应该渲染一个包含<code>h1</code>标的<code>div</code>元素。
testString: assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return (mockedComponent.find('div').length === 1 && mockedComponent.find('h1').length === 1); })());
- text: 应使用<code>componentDidMount</code>的超时函数更新组件状态
- text: 组件 state 应该用<code>componentDidMount</code>中的延时函数更新。
testString: assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return new RegExp('setTimeout(.|\n)+setState(.|\n)+activeUsers').test(String(mockedComponent.instance().componentDidMount)); })());
- text: <code>h1</code>标应该从<code>MyComponent</code>的状态呈现<code>activeUsers</code>值。
- text: <code>h1</code>标应该从<code>MyComponent</code>的 state 渲染<code>activeUsers</code>值。
testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ activeUsers: 1237 }); return mockedComponent.find(''h1'').text(); }; const second = () => { mockedComponent.setState({ activeUsers: 1000 }); return mockedComponent.find(''h1'').text(); }; assert(new RegExp(''1237'').test(first()) && new RegExp(''1000'').test(second())); }; '
```
@ -57,7 +62,6 @@ class MyComponent extends React.Component {
);
}
};
```
</div>
@ -67,7 +71,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -77,8 +81,30 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
activeUsers: null
};
}
componentDidMount() {
setTimeout( () => {
this.setState({
activeUsers: 1273
});
}, 2500);
}
render() {
return (
<div>
<h1>Active Users: {this.state.activeUsers}</h1>
</div>
);
}
};
```
/section>
</section>

View File

@ -3,24 +3,39 @@ id: 5a24c314108439a4d403617c
title: Use the Lifecycle Method componentWillMount
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 使用生命周期方法componentWillMount
forumTopicId: 301423
localeTitle: 使用生命周期方法componentWillMount
---
## Description
<section id="description"> React组件有几种特殊方法可以在组件生命周期的特定点执行操作。这些称为生命周期方法或生命周期钩子允许您在特定时间点捕获组件。这可以在渲染之前更新之前接收道具之前卸载之前等等。以下是一些主要生命周期方法的列表 <code>componentWillMount()</code> <code>componentDidMount()</code> <code>componentWillReceiveProps()</code> <code>shouldComponentUpdate()</code> <code>componentWillUpdate()</code> <code>componentDidUpdate()</code> <code>componentWillUnmount()</code>接下来的几节课将介绍这些生命周期方法的一些基本用例。 </section>
<section id='description'>
React 组件有几种特殊方法,可以在组件生命周期的特定点执行操作。这些称为生命周期方法或生命周期钩子,允许你在特定时间点捕获组件。这可以在渲染之前、更新之前、接收 props 之前、卸载之前等等。以下是一些主要生命周期方法的列表:
<code>componentWillMount()</code>
<code>componentDidMount()</code>
<code>shouldComponentUpdate()</code>
<code>componentDidUpdate()</code>
<code>componentWillUnmount()</code>
接下来的几节课将讲述这些生命周期方法的一些基本用例。
<strong>注意:</strong> `componentWillMount` 生命周期方法会在版本 16.X 废弃在版本 17 移除 [(Source)](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html)
</section>
## Instructions
<section id="instructions">在将组件装载到DOM时<code>render()</code>方法之前调用<code>componentWillMount()</code>方法。在<code>componentWillMount()</code>中将某些内容记录到控制台 - 您可能希望打开浏览器控制台以查看输出。 </section>
<section id='instructions'>
当组件被挂载到 DOM 时,<code>componentWillMount()</code>方法在<code>render()</code>方法之前被调用。在<code>componentWillMount()</code>中将一些内容记录到控制台--你需要打开浏览器控制台以查看输出。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>MyComponent</code>应该呈现<code>div</code>元素。
- text: <code>MyComponent</code>应该渲染一个<code>div</code>元素。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find('div').length === 1; })());
- text: 应该在<code>componentWillMount</code>调用<code>console.log</code>
- text: 应该在<code>componentWillMount</code>调用<code>console.log</code>。
testString: assert((function() { const lifecycle = React.createElement(MyComponent).type.prototype.componentWillMount.toString().replace(/ /g,''); return lifecycle.includes('console.log('); })());
```
@ -46,7 +61,6 @@ class MyComponent extends React.Component {
return <div />
}
};
```
</div>
@ -56,7 +70,7 @@ class MyComponent extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<MyComponent />, document.getElementById('root'))
```
</div>
@ -66,8 +80,21 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
componentWillMount() {
// change code below this line
console.log('Component is mounting...');
// change code above this line
}
render() {
return <div />
}
};
```
/section>
</section>

View File

@ -3,15 +3,20 @@ id: 5a24c314108439a4d4036168
title: Write a React Component from Scratch
challengeType: 6
isRequired: false
videoUrl: ''
localeTitle: 从Scratch写一个React组件
forumTopicId: 301424
localeTitle: 从零开始写一个 React 组件
---
## Description
<section id="description">现在您已经学习了JSX和React组件的基础知识现在是时候自己编写一个组件了。 React组件是React应用程序的核心构建块因此非常熟悉编写它们非常重要。请记住典型的React组件是扩展<code>React.Component</code>的ES6 <code>class</code> 。它有一个返回HTML来自JSX<code>null</code>的render方法。这是React组件的基本形式。一旦你理解了这一点你就会准备开始构建更复杂的React项目。 </section>
<section id='description'>
现在你已经了解了 JSX 和 React 组件的基础知识现在是时候自己编写一个组件了。React 组件是 React 应用程序的核心组成部分,因此熟练编写它们是非常重要的。记住,典型的 React 组件是 ES6<code>class</code>,它扩展了<code>React.Component</code>。它有一个返回 HTML从 JSX 返回)或<code>null</code>的渲染方法,这是 React 组件的基本形式。一旦你深刻地理解了这一点,你就可以开始构建更复杂的 React 项目了。
</section>
## Instructions
<section id="instructions">定义一个扩展<code>React.Component</code>的类<code>MyComponent</code> 。它的render方法应该返回一个<code>div</code> ,其中包含一个带有文本的<code>h1</code>标签: <code>My First React Component!</code>在里面。准确使用此文本,案例和标点符号很重要。确保也调用组件的构造函数。使用<code>ReactDOM.render()</code>将此组件呈现给DOM。有一个<code>div</code> <code>id=&#39;challenge-node&#39;</code>可供您使用。 </section>
<section id='instructions'>
定义一个<code>MyComponent</code>类,它是<code>React.Component</code>的扩展。它的渲染方法应该返回一个<code>div</code>,其中包含一个<code>h1</code>标签,标签文本为:<code>My First React Component!</code>。请确保文本内容、大小写和标点符号正确,以及调用了组件的构造函数。
使用<code>ReactDOM.render()</code>把该组件渲染到 DOM 中。有一个<code>id='challenge-node'</code><code>div</code>可供你使用。
</section>
## Tests
<section id='tests'>
@ -20,9 +25,9 @@ localeTitle: 从Scratch写一个React组件
tests:
- text: 应该有一个名为<code>MyComponent</code>的React组件。
testString: getUserInput => assert(getUserInput('index').replace(/\s/g, '').includes('classMyComponentextendsReact.Component{'));
- text: <code>MyComponent</code>应该包含带有文本<code>My First React Component!</code>的<code>h1</code>标签<code>My First React Component!</code>案例和标点符号问题
- text: <code>MyComponent</code>应该包含一个<code>h1</code>标签,标签的文本为<code>My First React Component!</code>,区分大小写并有标点符号。
testString: assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find('h1').text() === 'My First React Component!'; })());
- text: <code>MyComponent</code>应该呈现给DOM。
- text: <code>MyComponent</code>应该渲染到 DOM。
testString: assert(document.getElementById('challenge-node').childNodes.length === 1);
```
@ -48,8 +53,23 @@ tests:
## Solution
<section id='solution'>
```js
// solution required
// change code below this line
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h1>My First React Component!</h1>
</div>
);
}
};
ReactDOM.render(<MyComponent />, document.getElementById('challenge-node'));
```
/section>
</section>

View File

@ -3,30 +3,35 @@ id: 5a24c314108439a4d4036177
title: Write a Simple Counter
challengeType: 6
isRequired: false
videoUrl: ''
forumTopicId: 301425
localeTitle: 写一个简单的计数器
---
## Description
<section id="description">您可以通过结合到目前为止所涵盖的概念来设计更复杂的有状态组件。这些包括初始化<code>state</code> ,编写设置<code>state</code>方法,以及分配单击处理程序以触发这些方法。 </section>
<section id='description'>
你可以结合目前为止所涵盖的概念来设计更复杂的有状态组件。这包括初始化<code>state</code>,编写设置<code>state</code>的方法,以及指定单击处理程序来触发这些方法。
</section>
## Instructions
<section id="instructions"><code>Counter</code>组件跟踪一个的<code>count</code>的价值<code>state</code> 。有两个按钮调用方法<code>increment()</code><code>decrement()</code> 。编写这些方法以便在单击相应按钮时计数器值递增或递减1。此外创建一个<code>reset()</code>方法以便在单击重置按钮时计数设置为0. <strong>注意:</strong>确保不要修改按钮的<code>classNames</code> 。另外,请记住在构造函数中为新创建的方法添加必要的绑定。 </section>
<section id='instructions'>
<code>Counter</code>组件跟踪<code>state</code>中的<code>count</code>值。有两个按钮分别调用<code>increment()</code><code>decrement()</code>方法。编写这些方法,使计数器值在单击相应按钮时增加或减少 1。另外创建一个<code>reset()</code>方法,当单击 reset 按钮时,把计数设置为 0。
<strong>注意:</strong>&nbsp;确保你没有修改按钮的<code>classNames</code>。另外,请记住在构造函数中为新创建的方法添加必要的绑定。
</section>
## Tests
<section id='tests'>
```yml
tests:
- text: <code>Counter</code>应返回一个<code>div</code>元素,其中包含三个按钮,文本内容按此顺序<code>Increment!</code> <code>Decrement!</code> <code>Reset</code>
- text: <code>Counter</code>应返回一个<code>div</code>元素,包含三个按钮,按钮内容依次是<code>Increment!</code><code>Decrement!</code><code>Reset</code>。
testString: assert((() => { const mockedComponent = Enzyme.mount(React.createElement(Counter)); return (mockedComponent.find('.inc').text() === 'Increment!' && mockedComponent.find('.dec').text() === 'Decrement!' && mockedComponent.find('.reset').text() === 'Reset'); })());
- text: <code>Counter</code>的状态应该在<code>count</code>属性设置为<code>0</code>的情况下初始化
- text: <code>Counter</code>应该使用设置为<code>0</code><code>count</code>属性初始化 state
testString: 'const mockedComponent = Enzyme.mount(React.createElement(Counter)); assert(mockedComponent.find("h1").text() === "Current Count: 0")'
- text: 单击增量按钮应将计数增加<code>1</code>
- text: 单击 increment 按钮应将计数增加<code>1</code>。
testString: 'const mockedComponent = Enzyme.mount(React.createElement(Counter)); mockedComponent.find(".inc").simulate("click"); assert(mockedComponent.find("h1").text() === "Current Count: 1")'
- text: 单击减量按钮应将计数减<code>1</code>
- text: 单击 decrement 按钮应将计数减<code>1</code>。
testString: 'const mockedComponent = Enzyme.mount(React.createElement(Counter)); mockedComponent.find(".dec").simulate("click"); assert(mockedComponent.find("h1").text() === "Current Count: -1")'
- text: 单击重置按钮应将计数重置为<code>0</code>
- text: 单击 reset 按钮应将计数重置为<code>0</code>。
testString: 'const mockedComponent = Enzyme.mount(React.createElement(Counter)); mockedComponent.setState({ count: 5 }); const currentCountElement = mockedComponent.find("h1"); assert(currentCountElement.text() === "Current Count: 5"); mockedComponent.find(".reset").simulate("click"); assert(currentCountElement.text() === "Current Count: 0");'
```
@ -63,7 +68,6 @@ class Counter extends React.Component {
);
}
};
```
</div>
@ -73,7 +77,7 @@ class Counter extends React.Component {
<div id='jsx-teardown'>
```js
console.info('after the test');
ReactDOM.render(<Counter />, document.getElementById('root'))
```
</div>
@ -83,8 +87,44 @@ console.info('after the test');
## Solution
<section id='solution'>
```js
// solution required
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
this.increment = this.increment.bind(this);
this.decrement = this.decrement.bind(this);
this.reset = this.reset.bind(this);
}
reset() {
this.setState({
count: 0
});
}
increment() {
this.setState(state => ({
count: state.count + 1
}));
}
decrement() {
this.setState(state => ({
count: state.count - 1
}));
}
render() {
return (
<div>
<button className='inc' onClick={this.increment}>Increment!</button>
<button className='dec' onClick={this.decrement}>Decrement!</button>
<button className='reset' onClick={this.reset}>Reset</button>
<h1>Current Count: {this.state.count}</h1>
</div>
);
}
};
```
/section>
</section>