Files
Shaun Hamilton c2a11ad00d feat: add 'back/front end' in curriculum (#42596)
* chore: rename APIs and Microservices to include "Backend" (#42515)

* fix typo

* fix typo

* undo change

* Corrected grammar mistake

Corrected a grammar mistake by removing a comma.

* change APIs and Microservices cert title

* update title

* Change APIs and Microservices certi title

* Update translations.json

* update title

* feat(curriculum): rename apis and microservices cert

* rename folder structure

* rename certificate

* rename learn Markdown

* apis-and-microservices -> back-end-development-and-apis

* update backend meta

* update i18n langs and cypress test

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>

* fix: add development to front-end libraries (#42512)

* fix: added-the-word-Development-to-front-end-libraries

* fix/added-the-word-Development-to-front-end-libraries

* fix/added-word-development-to-front-end-libraries-in-other-related-files

* fix/added-the-word-Development-to-front-end-and-all-related-files

* fix/removed-typos-from-last-commit-in-index.md

* fix/reverted-changes-that-i-made-to-dependecies

* fix/removed xvfg

* fix/reverted changes that i made to package.json

* remove unwanted changes

* front-end-development-libraries changes

* rename backend certSlug and README

* update i18n folder names and keys

* test: add legacy path redirect tests

This uses serve.json from the client-config repo, since we currently use
that in production

* fix: create public dir before moving serve.json

* fix: add missing script

* refactor: collect redirect tests

* test: convert to cy.location for stricter tests

* rename certificate folder to 00-certificates

* change crowdin config to recognise new certificates location

* allow translations to be used

Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com>

* add forwards slashes to path redirects

* fix cypress path tests again

* plese cypress

* fix: test different challenge

Okay so I literally have no idea why this one particular challenge
fails in Cypress Firefox ONLY. Tom and I paired and spun a full build
instance and confirmed in Firefox the page loads and redirects as
expected. Changing to another bootstrap challenge passes Cypress firefox
locally. Absolutely boggled by this.

AAAAAAAAAAAAAAA

* fix: separate the test

Okay apparently the test does not work unless we separate it into
a different `it` statement.

>:( >:( >:( >:(

Co-authored-by: Sujal Gupta <55016909+heysujal@users.noreply.github.com>
Co-authored-by: Noor Fakhry <65724923+NoorFakhry@users.noreply.github.com>
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com>
2021-08-13 21:57:13 -05:00

190 lines
4.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: 5a24c314108439a4d4036176
title: 使用 State 切換元素
challengeType: 6
forumTopicId: 301421
dashedName: use-state-to-toggle-an-element
---
# --description--
有時可能在更新狀態的時候想知道上一個狀態是什麼。 但是狀態更新是異步的,這意味着 React 可能會把多個 `setState()` 集中在一起批量更新。 所以計算下一個值時 `this.state` 或者 `this.props` 不能作爲當前值。 所以最好不要寫如下的代碼:
```jsx
this.setState({
counter: this.state.counter + this.props.increment
});
```
正確的做法是,給 `setState` 傳入一個函數,這個函數可以訪問 state 和 props。 給 `setState` 傳入函數可以保證 state 和 props 是正確的值。 代碼可以重寫爲這樣:
```jsx
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
如果只需要 `state`,那麼用下面沒有 `props` 的格式也是可以的:
```jsx
this.setState(state => ({
counter: state.counter + 1
}));
```
注意一定要把 object 放在括號裏,否則 JavaScript 會認爲這只是代碼片段。
# --instructions--
`MyComponent` 有一個初始值爲 `false``visibility` 屬性。 如果 `visibility` 的值爲 truerender 方法返回一個視圖,如果爲 false返回另一個視圖。
目前,無法更新組件 `state` 中的 `visibility` 屬性, 該值應在 true 和 false 之間來回切換。 按鈕上有一個單擊處理程序,它觸發一個名爲 `toggleVisibility()` 的類方法。 給函數傳入 `setState` 來定義此方法,以便 `visibility``state` 在調用方法時切換到相反的值。 如果 `visibility``false`,則該方法將其設置爲`true`,反之亦然。
最後,單擊按鈕以查看基於其 `state` 的組件的條件渲染。
**提示:** 不要忘記將 `this` 關鍵字綁定到 `constructor` 中的方法上!
# --hints--
`MyComponent` 應該返回一個 `div` 元素,其中包含一個 `button` 元素。
```js
assert.strictEqual(
Enzyme.mount(React.createElement(MyComponent)).find('div').find('button')
.length,
1
);
```
`MyComponent` 應該使用設置爲 `false``visibility` 屬性來初始化其 state。
```js
assert.strictEqual(
Enzyme.mount(React.createElement(MyComponent)).state('visibility'),
false
);
```
單擊按鈕元素應在 `true``false` 之間切換 `visibility` 屬性的狀態。
```js
(() => {
const mockedComponent = Enzyme.mount(React.createElement(MyComponent));
const first = () => {
mockedComponent.setState({ visibility: false });
return mockedComponent.state('visibility');
};
const second = () => {
mockedComponent.find('button').simulate('click');
return mockedComponent.state('visibility');
};
const third = () => {
mockedComponent.find('button').simulate('click');
return mockedComponent.state('visibility');
};
const firstValue = first();
const secondValue = second();
const thirdValue = third();
assert(!firstValue && secondValue && !thirdValue);
})();
```
應該給 `setState` 傳入一個匿名函數。
```js
const paramRegex = '[a-zA-Z$_]\\w*(,[a-zA-Z$_]\\w*)?';
assert(
new RegExp(
'this\\.setState\\((function\\(' +
paramRegex +
'\\){|([a-zA-Z$_]\\w*|\\(' +
paramRegex +
'\\))=>)'
).test(__helpers.removeWhiteSpace(code))
);
```
不要在 `setState` 裏面使用 `this`
```js
assert(!/this\.setState\([^}]*this/.test(code));
```
# --seed--
## --after-user-code--
```jsx
ReactDOM.render(<MyComponent />, document.getElementById('root'));
```
## --seed-contents--
```jsx
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
visibility: false
};
// Change code below this line
// Change code above this line
}
// Change code below this line
// Change code above this line
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>
);
}
}
}
```
# --solutions--
```jsx
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>
);
}
}
}
```