3週目

27692 ワード

🎮 ネットゲームの作成と学習
3週目:デジタル野球

1. import

import { hot } from '/...'
の{hot}は構造分解構文です.defaultとしてエクスポートされていない構成部品をインポートします.

2.Reactの繰り返し文


Reactは、繰り返し文を使用するときにmap関数を使用します.
          {['사과', '바나나','포도','귤','감'].map((v) => {
              return (
                <li>{v}</li>
              )
          })}

変化する部分を一列に並べて利用すればいいです.

これにより、重複文の配置を宣言できます.

オブジェクトとしても使用できます.かなり重要な関数です!

3.分離部品

                <ul>
                    {this.fruit.map((v, i) => {
                        return (
                            <div>
                                <li key={v.fruit + v.taste}>
                                    <b>{v.fruit}</b> - {i}
                                    <div>컨텐츠1</div>
                                    <div>컨텐츠2</div>
                                    <div>컨텐츠3</div>
                                    <div>컨텐츠4</div>
                                </li>
                            </div>
                        )
                    })}
                </ul>
このコード
Try.jsx
import React, { Component } from 'react';

class Try extends Component {
    render() {
        return (
            <div>
                <b>{v.fruit}</b> - {i}
                <div>컨텐츠1</div>
                <div>컨텐츠2</div>
                <div>컨텐츠3</div>
                <div>컨텐츠4</div>
            </div>
        );
    }
}

export default Try;
Try.jsxファイルを使用してコンポーネントを分離し、次のように表すことができます.
                <ul>
                    {this.fruit.map((v, i) => {
                        return (
                            <div>
                                <Try />
                            </div>
                        )
                    })}
                </ul>
この時はTryjsxコンポーネントでは、vおよびiは宣言されていません.そのため、もちろんエラーが発生します.
NumberBaseball.jsx
                    {this.fruit.map((v, i) => {
                        return (
                            <div>
                                <Try value={v} index={i} />
                            </div>
                        )
                    })}
Try.jsx
import React, { Component } from 'react';

class Try extends Component {
    render() {
        return (
            <div>
                <b>{this.props.v.fruit}</b> - {this.props.index}
                <div>컨텐츠1</div>
                <div>컨텐츠2</div>
                <div>컨텐츠3</div>
                <div>컨텐츠4</div>
            </div>
        );
    }
}

export default Try;
このようにpropsを指定すればいいです!この場合propsは、親コンテナからサブエレメントが受信する値です.したがって、propsの値を変更する場合は、親コンテナからアクセスする必要があります.
ただし、サブコンテナでprops値を変更する必要がある場合は、stateにpropsを入れて解決します.
const Try = memo(({ tryInfo }) => {
    const [result, setResult] = useState(tryInfo.result);
    
    const onClick = () => {
        setResult('1');
    }
    return (
        <li>
            <div>{tryInfo.try}</div>
            <div onClick={onClick}>{result}</div>
        </li>
    );
});

4.デジタル野球


1.クラス構成部品

import React, { Component } from 'react';
import Try from './Try';

function getNumbers() {
    // 숫자 네 개를 겹치지 않고 뽑아내는 함수
    const candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    const array = [];
    for (let i = 0; i < 4; i+= 1) {
        const chosen = candidate.splice(Math.floor(Math.random() * (9 - i)), 1)[0];
        array.push(chosen);
    }

    return array;
}

class NumberBaseball extends Component {
    state = {
        result: '',
        value: '',
        answer: getNumbers(),
        tries: [],
    };

    onSubmitForm = (e) => {
        const { value, tries, answer } = this.state;
        e.preventDefault();
        // 화살표 함수를 안 쓰면 this 사용 불가 (undefined)
        if(this.state.value === this.state.answer.join('')) {
            this.setState({
                result: '홈런!',
                tries: [...this.state.tries, { try: value, result: '홈런!'}],
                // 옛날 배열, 새로운 값 <- 의 형태!
            })
        } else {
            const answerArray = value.split('').map((v) => parseInt(v))
            let strike = 0;
            let ball = 0;
            if (this.state.tries.length >= 9) { // 10번 이상 틀렸을 때
                this.setState({
                    result: `10번 이상 실패! 답은 ${this.state.answer.join(',')}이었습니다.`
                });

                alert('신규 게임 시작')
                this.setState({
                    value: '',
                    answer: getNumbers(),
                    tries: [],
                });

            } else {
                for (let i = 0; i <4; i += 1) {
                    if (answerArray[i] === this.state.answer[i]) {
                        strike += 1;
                    }

                    else if (this.state.answer.includes(answerArray[i])) {
                        ball += 1;
                    }
                }
                this.setState({
                    tries: [...this.state.tries, { try: this.state.value, result: `${strike} 스트라이크, ${ball} 볼입니다.`}]
                })
            }
        }
    };

    onChangeInput = (e) => {
        console.log(this.state.answer);

        this.setState({
            value: e.target.value,
        });
    };;

    render() {
        return (
            <div>
                <h1>{this.state.result}</h1>
                <form onSubmit={this.onSubmitForm}>
                    <input maxLength={4} value={this.state.value} 
                        onChange={this.onChangeInput}/>
                </form>

                <div>시도: {this.state.tries.length}</div>

                <ul>
                    {this.state.tries.map((v, i) => {
                        return (
                            <Try key={`${i + 1}차 시도`} tryInfo={v} />
                        )
                    })}
                </ul>
            </div>
        );
    }
}

export default NumberBaseball;

2.関数構成部品

import React, { useState } from 'react';
import Try from './Try';

function getNumbers() {
    // 숫자 네 개를 겹치지 않고 뽑아내는 함수
    const candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    const array = [];
    for (let i = 0; i < 4; i+= 1) {
        const chosen = candidate.splice(Math.floor(Math.random() * (9 - i)), 1)[0];
        array.push(chosen);
    }
    return array;
}

const NumberBaseball = () => {
    const [result, setResult] = useState('');
    const [value, setVaule] = useState('');
    const [answer, setAnswer] = useState(getNumbers());
    const [tries, setTries] = useState('');

    const onSubmitForm = (e) => {
        e.preventDefault();
        // 화살표 함수를 안 쓰면 this 사용 불가 (undefined)
        if(value === answer.join('')) {
            setResult('홈런!');
            setTries((prevTries) => {
                return [...prevTries, { try: value, result: '홈런!'}]
            });

            alert('신규 게임 시작');
            setVaule('');
            setAnswer(getNumbers());
            setTries([]);

        } else { // 답 틀렸으면
            const answerArray = value.split('').map((v) => parseInt(v))
            let strike = 0;
            let ball = 0;
            if (tries.length >= 9) { // 10번 이상 틀렸을 때
                
                setResult(`10번 이상 실패! 답은 ${answer.join(',')}이었습니다.`);

                alert('신규 게임 시작')
                setVaule('');
                setAnswer(getNumbers());
                setTries([]);

            } else {
                for (let i = 0; i <4; i += 1) {
                    if (answerArray[i] === answer[i]) {
                        strike += 1;
                    }

                    else if (answer.includes(answerArray[i])) {
                        ball += 1;
                    }
                }

                setTries((prevTries) => [...prevTries, { try: value, result: `${strike} 스트라이크, ${ball} 볼입니다.`}],)
                setVaule('');
            }
        }
    };

    const onChangeInput = (e) => {
        setVaule(e.target.value);
    };;

    return (
        <div>
            <h1>{result}</h1>
            <form onSubmit={onSubmitForm}>
                <input maxLength={4} value={value} 
                    onChange={onChangeInput}/>
            </form>

            <div>시도: {tries.length}</div>

            <ul>
                {tries && tries.map((v, i) => {
                    return (
                        <Try key={`${i + 1}차 시도`} tryInfo={v} />
                    )
                })}
            </ul>
        </div>
    );
}

export default NumberBaseball;

5. shouldComponentUpdate

import React, { Component } from 'react';

class RenderTest extends Component {
    state = { 
        counter: 0,
    };

    onClick = () => {
        this.setState({});
    }

    render() {
        console.log('렌더링', this.state);

        return (
            <div>
                <button onClick={this.onClick}>클릭</button>
            </div>
        )
    }
}

export default RenderTest;

この時点で<クリック>ボタンを押すと、変化がなくてもレンダリングできます!
反応器ではsetStateを呼び出すだけでレンダリングできるからです.
この場合はshouldUpdateComponentを使用します.
    shouldComponentUpdate(nextProps, nextState, nextContext) {
        if(this.state.counter !== nextState.counter) {
            return true;
        }
        return false;
    }
shouldUpdate Componentを使用している場合は、変更がない場合はレンダリングされません.
このようにreactを使用する場合、最も多くの練習が最適化されます.
shouldUpdate Componentを使うのが面倒ならPureComponentも使えます.ただし、構成部品が複雑になると、使いにくくなる場合があります.

class RenderTest extends PureComponent {
    state = { 
        counter: 0,
    };

    onClick = () => {
        this.setState({});
    }

    render() {
        console.log('렌더링', this.state);

        return (
            <div>
                <button onClick={this.onClick}>클릭</button>
            </div>
        )
    }
}

export default RenderTest;
Hooksで同じ機能を実現する場合、React.memoを使えばいいです.
import React, { memo } from 'react';

const Try = memo(({ tryInfo }) => {
    return (
        <li>
            <div>{tryInfo.try}</div>
            <div>{tryInfo.result}</div>
        </li>
    );
});

export default Try;

追加


1.



これは、Hooksコンポーネントにコメントを追加したときに発生したエラーです.

エラーメッセージがMissingセミコロンだったので、どういう意味かと思っていたのですが、カッコでもう一度包むのを忘れてしまって発生したエラー…😥
今週の授業は思ったより難しかったので、何日も授業を受けました.復習を続けなければならない😲