|
@@ -0,0 +1,337 @@
|
|
|
+import logo from './logo.svg';
|
|
|
+import './App.css';
|
|
|
+import React, {useEffect, useState, useRef} from 'react';
|
|
|
+
|
|
|
+const MyDiv = () => {
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ Привет-привет!
|
|
|
+ <input />
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const _ = React.createElement
|
|
|
+
|
|
|
+const MyDivNoJSX = () => {
|
|
|
+ return _('div', {},
|
|
|
+ "Привет-привет!",
|
|
|
+ _('input'))
|
|
|
+}
|
|
|
+
|
|
|
+const MyDivNoJSX2 = () => {
|
|
|
+ return _('div', {children: [ "Привет-привет!", _('input')]})
|
|
|
+}
|
|
|
+
|
|
|
+console.log(<div id="id1" style={{color: 'red'}}>
|
|
|
+ потомки
|
|
|
+ <input/>
|
|
|
+ </div>)
|
|
|
+
|
|
|
+console.log(<div id="id1" style={{color: 'red'}} children={[
|
|
|
+ "потомки",<input/>]} /> )
|
|
|
+console.log(<MyDiv />)
|
|
|
+
|
|
|
+const TwoDivs = () =>
|
|
|
+<div>
|
|
|
+ <MyDiv />
|
|
|
+ <MyDiv />
|
|
|
+</div>
|
|
|
+
|
|
|
+const Add = ({a=100,b=1000}) =>
|
|
|
+<div>
|
|
|
+ a + b = {a} + {b} = {+a + +b}
|
|
|
+</div>
|
|
|
+
|
|
|
+const BlockOfTextWithHeader = ({children,title='No Title'}) =>
|
|
|
+<>
|
|
|
+ <h2>{title}</h2>
|
|
|
+ <p>
|
|
|
+ {children}
|
|
|
+ </p>
|
|
|
+</>
|
|
|
+
|
|
|
+const arr = ["Див 1", "Див 2"]
|
|
|
+const data = [
|
|
|
+ {children: '1111',title: 'адын-адын'},
|
|
|
+ {children: '2222',title: 'два-два'},
|
|
|
+ {children: '3333',title: 'тры-тры'},
|
|
|
+]
|
|
|
+
|
|
|
+const Counter = () => {
|
|
|
+ const [count, setCount] = useState(10)
|
|
|
+ console.log(count)
|
|
|
+ return (<button onClick={() => setCount(count +1)}>
|
|
|
+ {count}
|
|
|
+ </button>)
|
|
|
+}
|
|
|
+
|
|
|
+const TextLength = ({text}) => <h1>{text.length}</h1>
|
|
|
+
|
|
|
+const Input = () => {
|
|
|
+ const [text, setText] = useState('testtest')
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <input value={text}
|
|
|
+ onChange={e => setText(e.target.value.toUpperCase())}/>
|
|
|
+ <TextLength text={text} />
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const LoginForm = ({onLogin}) => {
|
|
|
+ //тут надо два состояния - для логина и для пароля;
|
|
|
+ const [stateLogin, setStateLogin] = useState("")
|
|
|
+ const [statePass, setStatePass] = useState("")
|
|
|
+ //кнопка логина должна быть disabled если одно из полей пустое
|
|
|
+ const disabled = stateLogin && statePass ? false : true
|
|
|
+ //по клику на кнопку запустить onLogin и передать туда
|
|
|
+ //текущее состояние login и password
|
|
|
+ return (
|
|
|
+ //<h1>тут вместо h1 должна быть верстка: два инпута и кнопка login</h1>
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ value={stateLogin}
|
|
|
+ onChange={e => setStateLogin(e.target.value)}
|
|
|
+ />
|
|
|
+ <input
|
|
|
+ value={statePass}
|
|
|
+ onChange={e => setStatePass(e.target.value)}
|
|
|
+ />
|
|
|
+ <button
|
|
|
+ disabled={disabled}
|
|
|
+ onClick = {() => onLogin(stateLogin, statePass)}
|
|
|
+ >
|
|
|
+ Login</button>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+/*Spoiler
|
|
|
+Реализуйте компонент Spoiler, скрывающий контент и открывающий его по клику. Компонент будет получать 3 пропс:
|
|
|
+header, который будет выводится всегда
|
|
|
+open, может быть true или false, если написать в JSX без значения, это значит open={true}
|
|
|
+вложенный контент, т. е. children, который отображается в открытом состоянии спойлера и не отображается в закрытом
|
|
|
+Изначально компонент имеет состояние переданное через пропс open По клику на <div> в котором будет отображаться header должно меняться состояние на противоположное Обеспечьте условие, которое будет показывать или нет children.*/
|
|
|
+
|
|
|
+const Spoiler = ({ header = "+", open = true, children }) => {
|
|
|
+ //напишите тут код
|
|
|
+ const [getOpen, setOpen] = useState(open)
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <div onClick={() => {
|
|
|
+ setOpen(!getOpen)
|
|
|
+ console.log(getOpen)
|
|
|
+ }}>
|
|
|
+ {header}
|
|
|
+ </div>
|
|
|
+ {getOpen && children}
|
|
|
+ </>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+class RangeInput extends React.Component {
|
|
|
+
|
|
|
+ constructor(props) {
|
|
|
+ super(props);
|
|
|
+ this.min = props.min
|
|
|
+ this.max = props.max
|
|
|
+ this.state = {
|
|
|
+ value: ""
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ changeValue(e){
|
|
|
+ this.setState({value: +e.target.value})
|
|
|
+ }
|
|
|
+
|
|
|
+ render() {
|
|
|
+ if (this.state.value !== "" && this.state.value < this.min || this.state.value > this.max) {
|
|
|
+ return <input value={this.state.value} onChange={ e => this.changeValue(e)} className= 'red' type='number'/>
|
|
|
+ }
|
|
|
+ return <input value={this.state.value} onChange={ e => this.changeValue(e)} type='number'/>
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*PasswordConfirm
|
|
|
+Реализовать компонент PasswordConfirm, отображающий два <input type='password'/> со следующими возможностями:
|
|
|
+prop min - минимальная длина пароля
|
|
|
+Используйте компонент-класс и setState для отслеживания и валидации совпадения паролей и проверки на длину.Или useState
|
|
|
+По желанию добавьте более хитрые валидации типа проверки на размеры буков и наличие цифр в пароле.*/
|
|
|
+
|
|
|
+class PasswordConfirm extends React.Component {
|
|
|
+ constructor(props){
|
|
|
+ super(props)
|
|
|
+ this.min = props.min
|
|
|
+ this.state = {
|
|
|
+ inputFirstValue: "",
|
|
|
+ inpitSecondValue: ""
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ changeValue1(e){
|
|
|
+ this.setState({inputFirstValue: e.target.value})
|
|
|
+ }
|
|
|
+ changeValue2(e){
|
|
|
+ this.setState({inpitSecondValue: e.target.value})
|
|
|
+ }
|
|
|
+
|
|
|
+ render() {
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ {this.state.inputFirstValue === "" ? <input value={this.state.inputFirstValue} onChange={e => this.changeValue1(e)} ></input>
|
|
|
+ : this.state.inputFirstValue.length < this.min ? <input value={this.state.inputFirstValue} onChange={e => this.changeValue1(e)} className="red"></input>
|
|
|
+ : this.state.inputFirstValue === this.state.inpitSecondValue ? <input value={this.state.inputFirstValue} onChange={e => this.changeValue1(e)} className="green"></input>
|
|
|
+ : <input value={this.state.inputFirstValue} onChange={e => this.changeValue1(e)} ></input>}
|
|
|
+
|
|
|
+ {this.state.inpitSecondValue === "" ? <input value={this.state.inpitSecondValue} onChange={e => this.changeValue2(e)}></input>
|
|
|
+ : this.state.inpitSecondValue.length < this.min ? <input value={this.state.inpitSecondValue} onChange={e => this.changeValue2(e)} className="red"></input>
|
|
|
+ : this.state.inputFirstValue === this.state.inpitSecondValue ? <input value={this.state.inpitSecondValue} onChange={e => this.changeValue2(e)} className="green"></input>
|
|
|
+ : <input value={this.state.inpitSecondValue} onChange={e => this.changeValue2(e)}></input>}
|
|
|
+
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*Timer
|
|
|
+Напишите компонент, в который передается через props количество секунд, а компонент при этом реализует обратный отсчет раз в секунду уменьшая количество секунд на 1. Останавливается на 0. Добавьте в компонент кнопку паузы.
|
|
|
+Компонент должен отображать часы, минуты и секунды.*/
|
|
|
+
|
|
|
+function Timer({pauseState = true, sec}){
|
|
|
+ const [pause, setPause] = useState(pauseState)
|
|
|
+ const [time, setTime] = useState(sec)
|
|
|
+
|
|
|
+ let timeout
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (time > 0 && pause === false) {
|
|
|
+ timeout = setTimeout(() => {
|
|
|
+ console.log(time)
|
|
|
+ setTime(time - 1000)
|
|
|
+ }, 1000)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <div>{time/1000}</div>
|
|
|
+ <button onClick={()=>{clearTimeout(timeout); setPause(!pause)}}>пауза</button>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+/*TimerControl
|
|
|
+Напишите компонент, с тремя полями ввода (часы, минуты и секунды) и кнопкой Start, по которой будет стартовать компонент Timer*/
|
|
|
+
|
|
|
+function Timer2({sec=0}){
|
|
|
+ const [pause, setPause] = useState(false)
|
|
|
+ const [time, setTime] = useState(sec)
|
|
|
+ console.log('Timer2' , time)
|
|
|
+
|
|
|
+ useEffect(()=>setTime(sec), [sec])
|
|
|
+
|
|
|
+ const timeoutRef = useRef()
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (time > 0 && pause === false) {
|
|
|
+ timeoutRef.current = setTimeout(() => {
|
|
|
+ console.log(time)
|
|
|
+ setTime(time - 1000)
|
|
|
+ }, 1000)
|
|
|
+ console.log('timeout', timeoutRef.current)
|
|
|
+ }
|
|
|
+ }, [time, pause])
|
|
|
+
|
|
|
+ let pauseButtonText = pause ? "продолжить отсчёт" : "пауза"
|
|
|
+
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <div>{time/1000}</div>
|
|
|
+ <button onClick={()=>{console.log('pause', timeoutRef.current); clearTimeout(timeoutRef.current); setPause(!pause)}}>{pauseButtonText}</button>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+function TimerControl({f}) {
|
|
|
+ const [hours, setHours] = useState()
|
|
|
+ const [minutes, setMinutes] = useState()
|
|
|
+ const [seconds, setSeconds] = useState()
|
|
|
+
|
|
|
+
|
|
|
+ console.log(seconds)
|
|
|
+ const setTimer = () => {
|
|
|
+
|
|
|
+ console.log(seconds)
|
|
|
+ let value = seconds * 1000
|
|
|
+ console.log(value)
|
|
|
+ console.log(f)
|
|
|
+ f(value)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ return(
|
|
|
+ <div>
|
|
|
+ <span>Hours:</span>
|
|
|
+ <input type="number" min={0} max={24} value={hours} onChange={(e)=>setHours(e.target.value)}/>
|
|
|
+ <span>Minutes:</span>
|
|
|
+ <input type="number" min={0} max={60} value={minutes} onChange={(e)=>setMinutes(e.target.value)}/>
|
|
|
+ <span>Seconds:</span>
|
|
|
+ <input type="number" min={0} max={60} value={seconds} onChange={(e)=>setSeconds(e.target.value)}/>
|
|
|
+ <button onClick={setTimer}>START TIMER</button>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function App() {
|
|
|
+const[timer, setTimer] = useState()
|
|
|
+
|
|
|
+console.log('app timer state',timer)
|
|
|
+
|
|
|
+const fCallbackTimer = useRef((value) => setTimer(value))
|
|
|
+console.log("проверка" , fCallbackTimer.current)
|
|
|
+ return (
|
|
|
+ <div className="App">
|
|
|
+ <header className="App-header" >
|
|
|
+ {Math.random() > 0.5 && <div children={`
|
|
|
+ много
|
|
|
+
|
|
|
+ много
|
|
|
+
|
|
|
+ строк`} />}
|
|
|
+ <MyDiv />
|
|
|
+ <MyDivNoJSX />
|
|
|
+ </header>
|
|
|
+ <Spoiler header={<h1>Заголовок</h1>} open>
|
|
|
+ Контент 1
|
|
|
+ <p>
|
|
|
+ лорем ипсум траливали и тп.
|
|
|
+ </p>
|
|
|
+ </Spoiler>
|
|
|
+
|
|
|
+
|
|
|
+ <Spoiler>
|
|
|
+ <h2>Контент 2</h2>
|
|
|
+ <p>
|
|
|
+ лорем ипсум траливали и тп.
|
|
|
+ </p>
|
|
|
+ </Spoiler>
|
|
|
+ <RangeInput min={2} max={10} />
|
|
|
+ <LoginForm onLogin={(l,p) => console.log('LOGIN: ', l, ' PASSWORD: ', p)} />
|
|
|
+ <PasswordConfirm min = {5}/>
|
|
|
+ <Timer sec={50000}/>
|
|
|
+ <Timer2 sec={timer}/>
|
|
|
+ <TimerControl f={fCallbackTimer.current}/>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+export default App;
|