Files
freeCodeCamp/curriculum/challenges/chinese-traditional/03-front-end-development-libraries/react/create-a-controlled-form.md
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

221 lines
6.0 KiB
Markdown
Raw 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: 5a24c314108439a4d4036179
title: 創建一個可以控制的表單
challengeType: 6
forumTopicId: 301384
dashedName: create-a-controlled-form
---
# --description--
上一個挑戰展示了 React 能控制某些元素的內部 state比如 `input``textarea`,這使得這些元素成爲受控組件。 這也適用於其他表單元素,包括常規的 HTML 表單 `form` 元素。
# --instructions--
`MyForm` 組件中是一個帶有提交處理程序的空 `form` 元素, 提交處理程序將在提交表單時被調用。
我們增加了一個提交表單的按鈕。 可以看到它的 `type` 被設置爲 `submit`,表明它是控制表單提交的按鈕。 在 `form` 中添加 `input` 元素,並像上個挑戰一樣設置其 `value``onChange()` 屬性。 然後,應該完成 `handleSubmit` 方法,以便將組件 state 屬性 `submit` 設置爲本地 `state` 下的當前輸入值。
**注意:** 還必須在提交處理程序中調用 `event.preventDefault()`,以防止將會刷新網頁的默認的表單提交行爲。 爲了便於學員操作,默認行爲在這裏被禁用,以防止重置挑戰的代碼。
最後,在 `form` 元素之後創建一個 `h1` 標籤,該標籤從組件的 `state` 渲染 `submit` 的值。 然後,可以在表單中鍵入任何內容,然後單擊按鈕(或按 enter 鍵),輸入會渲染到頁面上。
# --hints--
`MyForm` 應該返回一個包含 `form``h1` 標籤的 `div` 元素, 其中,表單中應該包括一個 `input` 和一個 `button`
```js
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
);
})()
);
```
`MyForm` 的 state 應該用 `input``submit` 屬性初始化,且兩者都爲空字符串。
```js
assert(
Enzyme.mount(React.createElement(MyForm)).state('input') === '' &&
Enzyme.mount(React.createElement(MyForm)).state('submit') === ''
);
```
`input` 元素中的輸入應該會更新組件中 state 的 `input` 屬性。
```js
(() => {
const mockedComponent = Enzyme.mount(React.createElement(MyForm));
const _1 = () => {
mockedComponent.setState({ input: '' });
return mockedComponent.state('input');
};
const _2 = () => {
mockedComponent
.find('input')
.simulate('change', { target: { value: 'TestInput' } });
return {
state: mockedComponent.state('input'),
inputVal: mockedComponent.find('input').props().value
};
};
const before = _1();
const after = _2();
assert(
before === '' &&
after.state === 'TestInput' &&
after.inputVal === 'TestInput'
);
})();
```
提交表單應該運行 `handleSubmit`,它應該將 state 中的 `submit` 屬性設置爲當前輸入。
```js
(() => {
const mockedComponent = Enzyme.mount(React.createElement(MyForm));
const _1 = () => {
mockedComponent.setState({ input: '' });
mockedComponent.setState({ submit: '' });
mockedComponent
.find('input')
.simulate('change', { target: { value: 'SubmitInput' } });
return mockedComponent.state('submit');
};
const _2 = () => {
mockedComponent.find('form').simulate('submit');
return mockedComponent.state('submit');
};
const before = _1();
const after = _2();
assert(before === '' && after === 'SubmitInput');
})();
```
`handleSubmit` 應該調用 `event.preventDefault`
```js
assert(
__helpers.isCalledWithNoArgs(
'event.preventDefault',
MyForm.prototype.handleSubmit.toString()
)
);
```
`h1` 標頭應該從組件的 state 渲染 `submit` 字段的值。
```js
(() => {
const mockedComponent = Enzyme.mount(React.createElement(MyForm));
const _1 = () => {
mockedComponent.setState({ input: '' });
mockedComponent.setState({ submit: '' });
mockedComponent
.find('input')
.simulate('change', { target: { value: 'TestInput' } });
return mockedComponent.find('h1').text();
};
const _2 = () => {
mockedComponent.find('form').simulate('submit');
return mockedComponent.find('h1').text();
};
const before = _1();
const after = _2();
assert(before === '' && after === 'TestInput');
})();
```
# --seed--
## --after-user-code--
```jsx
ReactDOM.render(<MyForm />, document.getElementById('root'));
```
## --seed-contents--
```jsx
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) {
// Change code below this line
// Change code above this line
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
{/* Change code below this line */}
{/* Change code above this line */}
<button type='submit'>Submit!</button>
</form>
{/* Change code below this line */}
{/* Change code above this line */}
</div>
);
}
}
```
# --solutions--
```jsx
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(state => ({
submit: 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>
);
}
}
```