Фронтенд разработка на ReactJs./ ReactJs. Свойства и события компонента.

Теги: event js props react

ReactJs. Свойства и события компонента.

Теперь когда мы отобразили пост и комментарии при помощи html статично внутри компонента, можно поговорить о том как эти данные передавать компоненту и отображать в шаблоне динамично.

В последствии мы будем забирать из с API на сервере, но сейчас определим их как json объект внутри функции-компонента.

Пример работы с переменными компонента.

export default function App() {
let currentTime = new Date().toLocaleTimeString();
return (
        <div className="App">
        <h1>Current time is</h1>
        <h2>{currentTime}</h2>
        </div>
    )
}

Как видим все что мы пишем внутри {} воспринимается как код js.

<h2>{currentTime}</h2>

Или написать код прямо внутри.

<h2>{new Date().toLocaleTimeString()}</h2>

Ничто не мешает использовать цикл. Например так:

<ul>{ array.map( (el) => `<li>${el.name}</li>`) }</ul>

Или даже использовать компонент внутри и передать ему данные.

<ul>{ array.map( (el) => <Post author=${el.name} />) }</ul>

Извлечение переданных аргументов.

export default function Post(props) {

return (
        <p>
        Author: {props.author}
        </p>
    )
}

Мы можем легко извлечь их и в переменную.

function Post(props){
    let author = props.author;
    ...
}

В классовых компонентах извлекаем через ключевое слово this.

this.props.autor

Деструктуризация.

Массив

let arr = [7, 88, -3];
/*
 a = 7
 b = 88
 c = -3
*/
let [a, b, c] = arr;

Объект

let obj = {name:"Bill", lastName:"White"};
let {name,lastName} = obj;

let user = {name:”Dan”,lastName:”Brown”};
let {...concreteU} = user;
console.log(concreteU);

Оператор spread

let arr = [7, 88, -3];
/*
 f = 7
 arr2 = [88,-3]
*/
let [f, ...arr2] = arr;

В компоненте.

export default function App(props) {
 /*
 деструктурируем объект props
 */
 let { name, lastName } = props;
...

Передача объекта компоненту с помощью спред-оператора.

let writers = [
    { name: “Dan”, lastName: “Brown” },
    { name: “Joanne”, lastName: “Rowling” },
    { name: “Stephen”, lastName: “King” }
];
...
<Writer {...writers[0]} />
<Writer {...writers[1]} />
<Writer {...writers[2]} />
..

Либо циклом.

function WritersList(props) {
    return (
        <div>
            {writers.map(item => <Writer {...item} />)}
        </div>
    );
}

Информация о писателе будет передана внутрь компоненты через props.

function Writer(props) {
return (
    <>
        <div>
        {props.name} {props.lastName}
        </div>
        <hr/>
    
);

Значения по умолчанию.

App.defaultProps = { 
                    name: "William",
                    lastName: "Shakespeare" 
};

Установка стилей внутри компонента.

function Intro() {
    return <p style={{ color: "green" }}>
    Some intro text</p>;
}

Обработчик события.

function handlerClick() {
    alert("You clicked the button");
}
....

return (
        <button onClick={handlerClick}>
            Click me
        </button>
    )
}

Передача обработчика из дочернего компонента в родительский.

При передаче данных дочернему компоненту можно так же в виде props передавать и функции.

function doClick() {...}

<Post  handleClick={doClink} />

При этом внутри компонента Post надо будет определить функцию handleClick.

Post() {

    const doClick = function() {...}

    return (
        <button onClick={doClick} ></button>
    )
}

Можно также из дочернего компонента напрямую нагло вызвать обработчит из props!

var Child = React.createClass({
  render: function () {
    return <button onClick={this.props.onClick}>{this.props.text}</button>;
  },
});

Перед этим передав этот обработчит из родительского компонента.

var Parent = React.createClass({
  getInitialState: function() {
     return {childText: "Click me! (parent prop)"};
  },
  render: function () {
    return (
      <Child onClick={this.handleChildClick} text={this.state.childText}/>
    );
  },
  handleChildClick: function(event) {
     ...
  }
});

Состояния.

Это то, что меняется.

Функциональный компонент

Напрямую менять state нельзя! Его меняют через специальную функцию т.к. реакт должен отслеживать изменения и перерисовывать компоненты соответственно ним.

Мало того, при создании state необходимо использовать специальную функцию useState.

Эта функция-хук возвращает 2 вещи:

  • переменную state;

  • функцию для изменения state.

    useState(начальное_значение_для состояния)

Сигнатура использования.

const [counterVal, setCounterVal] = useState(0);

Пример использования

function Button() {
    const [bkColor, setBkColor] = useState("yellow");
    const [text, setText] = useState("Click me");
    const btnClick = () => {
        setBkColor("red");
        setText("You clicked me");
    };
}
return (
    <button
        style={{ backgroundColor: bkColor, height: "30px"}}
        onClick={btnClick}>
        {text}
    </button>
)

Несколько важных правил по работе с хуками:

  1. Используйте хуки только на верхнем уровне. Это означает, что надо ставить хук в начале кода функционального компонента.

  2. Не используйте хуки внутри циклов, условных операторов или вложенных функций. Вместо этого всегда используйте хуки только на верхнем уровне React-функций.

  3. Не вызывайте хуки из обычных функций JavaScript

Классовый компонент

import React from "react";
class Counter extends React.Component {
constructor(props) {
        super(props);
        this.state = {
            currentValue: 0
        }
    }
};

render() {
    const handlerClick = () => {
        this.setState({currentValue:
            this.state.currentValue +1 
        });
    };

return <button onClick={handlerClick}>
        {this.state.currentValue}
    </button>;
}

export default class App extends React.Component {
    render() {
        return (
        <>
            <Counter />
        
);

Предотвращение отправки формы и получение значения элемента.

function Form() {
    const handleSubmit = event => {
    /*
    Отменяем реакцию обработчика по умолчанию
    */
    event.preventDefault();
    /*
    Получаем доступ к текстовому полю
    */
    let uName = document.getElementById(“userName”);
    alert(uName.value);
};
...

Рефы

Служат для связки значений формы с переменными.

Пример использования.

...

let uRef = React.createRef();

const handleSubmit = event => {
    event.preventDefault();
    alert(uRef.current.value);
};
}
return (
    <form onSubmit={handleSubmit}>
    <input type=”text” id=”userName” ref={uRef} />
    <input type=”submit” value=”Click me” />
    </form>
);

Отслеживаем изменение поля формы.

import React, { useState } from “react”;
import “./styles.css”;
function Form() {
    const [nameState, setNameState] = useState(“”);
    const handlerSubmit = event => {
        event.preventDefault();
        alert(nameState);
    };
    const handlerChange = event => {
        setNameState(event.target.value);
    };
    return (
        <form onSubmit={handlerSubmit}>
            <input
            type=”text”
            placeholder=”Input name”
            value={nameState}
            onChange={handlerChange}
            required
            />
            <input type=”submit” value=”Click me” />
        </form>
    );
}
export default function App() {
return (
    <>
        <Form />
    
);
}

Отслеживаем чекбокс.

const [news, setNews] = useState(true);
...
const handlerSubmit = event => {
event.preventDefault();

    if (news === true) {
        msg = "Thank you for subscription!\n";
    }

};

const handlerChanged = event => {
const target = event.target;
/*
Проверяем для какого элемента возникло событие
*/
target.name === "aboutNews"
    ? setNews(event.target.checked)
    : setEmail(target.value);
};

...
<input
    type="checkbox"
    name="aboutNews"
    checked={news}
    onChange={handlerChanged}
/>

Маршрутизатор

Установка.

npm install react-router-dom

Использование.

import React from "react";
import { BrowserRouter as Router, Route, Switch }
from "react-router-dom";
import "./styles.css";

function Main() {
    return <h2>Main</h2>;
}

function AboutCompany() {
    return <h2>About company</h2>;
}
function News() {
    return <h2>Our news</h2>;
}
function NotFound() {
    return <h2>Not found</h2>;
}
export default function App() {
    return (
        <div>
        <Router>
            <Switch>
                <Route exact path="/" component={Main} />
                <Route path="/about"
                component={AboutCompany} />
                <Route path="/news" component={News} />
                <Route component={NotFound} />
            </Switch>
        </Router>
        </div>
    );
}

Дочерние маршруты.

function News() {
return (
    <div>
        <h2>Our news</h2>
        <Switch>
            <Route path="/news/london"
            component={London}/>;
            <Route path="/news/berlin"
            component={Berlin}/>;
            <Route path="/news/paris"
            component={Paris}/>;
        </Switch>
    </div>
);
}

Компонент меню.

import {BrowserRouter as Router, Route, Switch, Link} from "react-router-dom";

function NavMenu() {
return (
    <>
        <Link to="/" className="links">
        Main
        </Link>
        <Link to="/about" className="links">
        About
        </Link>
        <Link to="/news" className="links">
        News
        </Link>
    
);
}

Передача параметров в роуте.

<Route path="/branches/:name" component={Branch} />

Передаем пост и комментарии.

Задать вопрос, прокомментировать.