#4 refの応用/反応速度試験


インフラのZero Choさんの講義を見て整理した内容です
https://www.inflearn.com/course/web-game-react

コード#コード#


クラスバージョン


ResponseCheck.jsx

import React, {Component} from 'react';

class ResponseCheck extends Component {
	state = {
		state : "waiting",
		message : "클릭해서 시작하세요.",
		result : []
	};	

	timeout;
	startTime;
	endTime;
	onClickScreen = () => {
		const {state, message, result} = this.state;
		if (state === "waiting") {
			this.setState({
				state : "ready",
				message : "초록색이 되면 클릭하세요.",
			});
			this.timeout = setTimeout(() => {
				this.setState({
					state : "now",
					message : "지금 클릭!"
				});
				this.startTime = new Date();
			}, Math.floor(Math.random() * 1000) + 2000);
		} else if (state == "ready") { // 성급하게 클릭
			clearTimeout(this.timeout);
			this.setState({
				state : "waiting",
				message : "성급하시군요!",
				result : [],
			})
		} else if (state == "now") { // 반응속도 체크
			this.endTime = new Date();
			this.setState((prevState) => {
				return {
					state : "waiting",
					message : "클릭해서 시작하세요.",
					result : [...prevState.result, this.endTime - this.startTime],
				} 	
			})
		}
	}
	renderAverage = () => {
		const {result} = this.state;
		console.log(result);
		return result.length === 0
		? null 
		: <div>평균 시간 : {result.reduce((a, c) => a + c) / result.length}ms</div>
	};

	Reset = () => {
		this.setState({
			result : [],
		})
	}
	render() {
		return (
			<>
			<div id="screen" className={this.state.state} onClick={this.onClickScreen}>
				{this.state.message}
			</div>
			{this.renderAverage()}
			<button onClick={this.Reset}>리셋</button>
			</>
		)
	}
}

export default ResponseCheck;

関数のバージョン


ResponseCheck.jsx

const ResponseCheck = () => {
	const [state, setState] = useState("waiting");
	const [message, setMessage] = useState("클릭해서 시작하세요.");
	const [result, setResult] = useState([]);
	const timeout = useRef(null);
	const startTime = useRef();
	const endTime = useRef();
	const onClickScreen = () => {
		if (state === "waiting") {
			setState("ready");
			setMessage("초록색이 되면 클릭하세요.");
			timeout.current = setTimeout(() => {
				setState("now");
				setMessage("지금 클릭!");
				startTime.current = new Date();
			}, Math.floor(Math.random() * 1000) + 2000);
		} else if (state == "ready") { // 성급하게 클릭
			clearTimeout(timeout.current);
			setState("waiting");
			setMessage("성급하셨군요!");
		} else if (state == "now") { // 반응속도 체크
			endTime.current = new Date();
			setState("waiting");
			setMessage("클릭해서 시작하세요."); 
			setResult((prevResult) =>  {
				return [...prevResult, endTime.current - startTime.current]
			});
		}
	}
	const renderAverage = () => {
		return result.length === 0
		? null 
		: <div>평균 시간 : {result.reduce((a, c) => a + c) / result.length}ms</div>
	};

	const Reset = () => {
				setResult([]);
			}
	return (
		<>
			<div id="screen" className={state} onClick={onClickScreen}>
				{message}
			</div>		
			{renderAverage()}
			<button onClick={Reset}>리셋</button>
			</>
	)
}

#4-1反応条件文


反応素子のレンダリングでは、for、ifは使用できません.
  • は、異なる方法で表現されなければならない.
  • import React, {Component, useRef, useState, memo, createRef} from 'react';
    
    class ResponseCheck extends Component {
    	state = {
    		state : "waiting",
    		message : "클릭해서 시작하세요.",
    		result : []
    	};	
    	render() {
    		return (
    			<>
    			<div id="screen" className={this.state.state} onClick={this.onClickScreen}>
    				{this.state.message}
    			</div>
    			{this.state.result.length === 0 ? null : <div>평균 시간 : {this.state.result.reduce((a, c) => a + c) / this.state.result.length}ms</div>
    			}
    			</>
    		)
    	}
    }
    
    export default ResponseCheck; 
    配列が空の場合、reduce関数は使用できません.
    ラベルは、3つの演算子を使用して我慢している場合にのみ表示されます.
  • {조건문 === 참 ? <div>태그</div> : null}
  • 保護演算子(&&)を使う方法もあります.
  • {조건문 === 참 && <div>태그</div>}
  • import React, {useRef, useState} from 'react';
    
    class ResponseCheck extends Component {
    	state = {
    		state : "waiting",
    		message : "클릭해서 시작하세요.",
    		result : []
    	};	
    
    	renderAverage = () => {
    		const {result} = this.state;
    		return result.length === 0
    		? null 
    		: <div>평균 시간 : {result.reduce((a, c) => a + c) / result.length}ms</div>
    	};
    	render() {
    		return (
    			<>
    			<div id="screen" className={this.state.state} onClick={this.onClickScreen}>
    				{this.state.message}
    			</div>
    			{this.renderAverage()}
    			</>
    		)
    	}
    }
    
    export default ResponseCheck;
    取り除く方法もあります.
    クラスコンポーネントのメソッドは常に矢印関数です!!

  • 関数構成部品
    const ResponseCheck = () => {
    	const [status, setStatus] = useState("waiting");
    	const [message, setMessage] = useState("클릭해서 시작하세요.");
    	const [result, setResult] = useState([]);
    	
    	const onClickScreen = () => {
    		
    	}
    	const renderAverage = () => {
    		return result.length === 0
    		? null 
    		: <div>평균 시간 : {result.reduce((a, c) => a + c) / result.length}ms</div>
    	};
    	return (
    		<>
    			<div id="screen" className={status} onClick={onClickScreen}>
    				{message}
    			</div>
    			{renderAverage()}
    			</>
    	)
    }
  • reduce()

    배열.reduce((누적값, 현잿값, 인덱스, 요소) => { return 결과 }, 초깃값);積算値なので多様に使えます.
    oneTwoThree = [1, 2, 3];
    result = oneTwoThree.reduce((acc, cur, i) => {
      console.log(acc, cur, i);
      return acc + cur;
    }, 0);
    // 0 1 0 현재까지 누적된 값은 0, 현재 가지고 있는 요소는 1, 해당 요소의 인덱스는 0번째
    // 1 2 1 현재까지 누적된 값은 1(0 + 1), 현재 가지고 있는 요소는 2, 해당 요소의 인덱스는 1번째
    // 3 3 2 현재까지 누적된 값은 3(1 + 2), 현재 가지고 있는 요소는 3, 해당 요소의 인덱스는 2번째
    console.log(result); // 6

    #4-2 settimeoutを加えて反応速度を調べる


    this.state, this.propsのようによく使われる文法は,最初から構造分解が望ましい.
    import React, {Component, useRef, useState, memo, createRef} from 'react';
    
    class ResponseCheck extends Component {
    	state = {
    		state : "waiting",
    		message : "클릭해서 시작하세요.",
    		result : []
    	};	
    
    	timeout;
    	onClickScreen = () => {
    		const {state, message, result} = this.state;
    		if (state === "waiting") {
    			this.setState({
    				state : "ready",
    				message : "초록색이 되면 클릭하세요.",
    			});
    			this.timeout = setTimeout(() => {
    				this.setState({
    					state : "now",
    					message : "지금 클릭!"
    				})
    			}, Math.floor(Math.random() * 1000) + 2000);
    		} else if (state == "ready") { // 성급하게 클릭
    			clearTimeout(this.timeout);
    			this.setState({
    				state : "waiting",
    				message : "성급하시군요!",
    				result : [],
    			})
    		} else if (state == "now") { // 반응속도 체크
    			this.setState({
    				state : "waiting",
    				message : "클릭해서 시작하세요.",
    				result : [],
    			})
    		}
    	
    	}
    	renderAverage = () => {
    		const {result} = this.state;
    		return result.length === 0
    		? null 
    		: <div>평균 시간 : {result.reduce((a, c) => a + c) / result.length}ms</div>
    	};
    	render() {
    		return (
    			<>
    			<div id="screen" className={this.state.state} onClick={this.onClickScreen}>
    				{this.state.message}
    			</div>
    			{this.renderAverage()}
    			</>
    		)
    	}
    }
    
    export default ResponseCheck;
    クリック時の状態に応じて異なるdivを出力します.
    settimeoutが実行中に準備完了状態にある場合、「≪最初に戻る|First Return|emdw≫」をクリックすると、settimeoutはstateをnowに変更します.クラス内のオブジェクト(?)関数を代入し、cleartimeoutを使用して関数の実行を停止する必要があります.
    class ResponseCheck extends Component {
    	state = {
    		state : "waiting",
    		message : "클릭해서 시작하세요.",
    		result : []
    	};	
    
    	timeout;
    	startTime;
    	endTime;
    	onClickScreen = () => {
    		const {state, message, result} = this.state;
    		if (state === "waiting") {
    			this.setState({
    				state : "ready",
    				message : "초록색이 되면 클릭하세요.",
    			});
    			this.timeout = setTimeout(() => {
    				this.setState({
    					state : "now",
    					message : "지금 클릭!"
    				});
    				this.startTime = new Date();
    			}, Math.floor(Math.random() * 1000) + 2000);
    		} else if (state == "ready") { // 성급하게 클릭
    			clearTimeout(this.timeout);
    			this.setState({
    				state : "waiting",
    				message : "성급하시군요!",
    				result : [],
    			})
    		} else if (state == "now") { // 반응속도 체크
    			this.endTime = new Date();
    			this.setState((prevState) => {
    				return {
    					state : "waiting",
    					message : "클릭해서 시작하세요.",
    					result : [...prevState.result, this.endTime - this.startTime],
    				} 	
    			})
    		}
    	}
    	renderAverage = () => {
    		const {result} = this.state;
    		console.log(result);
    		return result.length === 0
    		? null 
    		: <div>평균 시간 : {result.reduce((a, c) => a + c) / result.length}ms</div>
    	};
    	render() {
    		return (
    			<>
    			<div id="screen" className={this.state.state} onClick={this.onClickScreen}>
    				{this.state.message}
    			</div>
    			{this.renderAverage()}
    			</>
    		)
    	}
    }
    new Dateを使用して、時間を含むオブジェクトを作成します.stateからnowになって計時を開始します.stateに設定すると、測定値のたびにsetStateに変更されてレンダリングされます.

  • 関数構成部品
    const ResponseCheck = () => {
    	const [state, setState] = useState("waiting");
    	const [message, setMessage] = useState("클릭해서 시작하세요.");
    	const [result, setResult] = useState([]);
    	
    	let timeout;
    	let startTime;
    	let endTime;
    	const onClickScreen = () => {
    		if (state === "waiting") {
    			setState("ready");
    			setMessage("초록색이 되면 클릭하세요.");
    
    			timeout = setTimeout(() => {
    				setState("now");
    				setMessage("지금 클릭!");
    				startTime = new Date();
    			}, Math.floor(Math.random() * 1000) + 2000);
    		} else if (state == "ready") { // 성급하게 클릭
    			clearTimeout(timeout);
    			setState("waiting");
    			setMessage("성급하셨군요!");
    			setResult([]);
    		} else if (state == "now") { // 반응속도 체크
    			endTime = new Date();
    			setState("waiting");
    			setMessage("클릭해서 시작하세요.");
    			setResult((prevState) =>  {return [...prevState, endTime - startTime]});
    		}
    	}
    	const renderAverage = () => {
    		return result.length === 0
    		? null 
    		: <div>평균 시간 : {result.reduce((a, c) => a + c) / result.length}ms</div>
    	};
    	return (
    		<>
    			<div id="screen" className={state} onClick={onClickScreen}>
    				{message}
    			</div>
    			{renderAverage()}
    			</>
    	)
    }
  • setTimeout()

    setTimeout(function() { //함수 코드}, delay);ヒステリシス(整数)ミリ秒後、関数を最初のパラメータとして実行します.setTimeout(() => { //함수 코드}, delay); setTimeout(() => { //호출될 (콜백)함수}, delay);矢印関数を使用するか、いっそ関数をパラメータとして挿入することもできます.

    #4-3性能検査とQ&A

    Reset = () => {
    		this.setState({
    			result : [],
    		})
    	}
    	render() {
    		return (
    			<>
    			<div id="screen" className={this.state.state} onClick={this.onClickScreen}>
    				{this.state.message}
    			</div>
    			{this.renderAverage()}
    			<button onClick={this.Reset}>리셋</button>
    			</>
    		)
    	}
    }
    ボタン機能を追加します.
    機能をメソッド(関数)に分離するよりも、サブコンポーネントを作成します.

    パフォーマンスの向上


    render()が実行され、コンポーネントの状態に変更がある場合、render内部のすべてのコンテンツが再レンダリングされます.
    関数構成部品でhookに設定されたステータス値を変更すると、関数全体が実行されます.
    すなわち、変更部分(state)が存在する場合、親コンポーネントにpureComponentを適用することは意味がありません.
    したがって、変更しない部分でサブエレメントを作成し、計算エレメントにする必要があります.

    #4-4応答速度チェック/Hooks変換

    import React, {Component, PureComponent, useRef, useState, memo, createRef} from 'react';
    
    const ResponseCheck = () => {
    	const [state, setState] = useState("waiting");
    	const [message, setMessage] = useState("클릭해서 시작하세요.");
    	const [result, setResult] = useState([]);
    	const timeout = useRef(null);
    	const startTime = useRef();
    	const endTime = useRef();
    	const onClickScreen = () => {
    		if (state === "waiting") {
    			setState("ready");
    			setMessage("초록색이 되면 클릭하세요.");
    			timeout.current = setTimeout(() => {
    				setState("now");
    				setMessage("지금 클릭!");
    				startTime.current = new Date();
    			}, Math.floor(Math.random() * 1000) + 2000);
    		} else if (state == "ready") { // 성급하게 클릭
    			clearTimeout(timeout.current);
    			setState("waiting");
    			setMessage("성급하셨군요!");
    		} else if (state == "now") { // 반응속도 체크
    			endTime.current = new Date();
    			setState("waiting");
    			setMessage("클릭해서 시작하세요."); 
    			setResult((prevResult) =>  {
    				return [...prevResult, endTime.current - startTime.current]
    			});
    		}
    	}
    	const renderAverage = () => {
    		return result.length === 0
    		? null 
    		: <div>평균 시간 : {result.reduce((a, c) => a + c) / result.length}ms</div>
    	};
    
    	const Reset = () => {
    				setResult([]);
    			}
    	return (
    		<>
    			<div id="screen" className={state} onClick={onClickScreen}>
    				{message}
    			</div>
    			{renderAverage()}
    			<button onClick={Reset}>리셋</button>
    			</>
    	)
    }
    
    export default ResponseCheck;
    関数構成部品に切り替え
    timeout、startTime、endTimeのタイミング
  • クラス-この属性は
  • です.
  • 関数-ref
  • を使用
    関数(hooks)は、クラスでthisで表される属性をrefとして表します.
    refを使用する場合は常に電流を使用します.(アクセスにより)

    stateとrefの違い


    「stateの変更」(setState)は、関数全体をレンダリングするために返された部分をレンダリングしますが、refの値を変更すると再レンダリングされません.
    値を変更しても画面に影響を与えたくない場合は、Refを使用します.
    RefでsetStateを使用しても画面は変わりません.

    #4-5 return内部使用for,if


    jsxで括弧({})を押すとJavaScriptコードを書くことができ、関数にifを書くことができる場合はfor、ifを使うことができます.
    return (
    		<>
    			<div id="screen" className={state} onClick={onClickScreen}>
    				{message}
    			</div>
    			{(() => {
    				if (result.length === 0) {
    					return null;
    				} else {
    					return <div>평균 시간 : {result.reduce((a, c) => a + c) / result.length}ms</div>
    				}
    			})()} {/* 즉시 실행해야 하기 때문에 ()붙여야 한다.*/}
    			{/* {renderAverage()} */}
    			<button onClick={Reset}>리셋</button>
    			</>
    	)
    そうするより、直接関数を減算したほうがいいのですが...
    mapの代わりにforを使用する場合は、上記の例のようにすぐに実行関数を作成できます.
    {(() => {
    const array = [];
    for (let i = 0; i < tries.length; i++) {
    	array.push(<태그></태그>);
    }
    	return array;
    }
    })()};
    すなわち、関数として減算するか、サブコンポーネントとして減算するか...
    return [
    	<div key="apple">apple</div>
    	<div key="peach">peach</div>
    	<div key="orange"orange</div>
    ]
    jsxを配列に読み込んで返すのは有効な構文です!
    いつも彼に鍵を貼ってあげなければならない.よく使う文法ではありません.