все вместе
React — это JS-библиотека для создания пользовательских интерфейсов, ядро которой сосредоточено на представлениях и направлено на реализацию разработки компонентов.
Так называемая компонентная разработка на самом деле похожа на укладку дерева, каждый компонент содержит свою логику и стиль, а затем объединяется вместе, чтобы завершить сложную страницу.
Основными особенностями компонентизации являются:Составной, многоразовый, ремонтопригодный
Итак, без лишних слов, давайте перейдем непосредственно к сегодняшней теме, используем официально рекомендованные скаффолдинги для сборки реактивного проекта и приступим к обучению.
create-реагировать-приложение запускает проект реагирования
первый шаг:Установить приложение create-реагировать глобальностроительные леса
npm i create-react-app -g
Шаг 2: Создайте реактивный проект
create-react-app 项目名
// 如:create-react-app react123
В результате вышеуказанных операций будет автоматически создан проект реакции с именем react123.В процессе создания леса автоматически установят для вас основной пакет реакции.реагировать и реагировать-дом, после завершения этого процесса вы можете перейти к третьему шагу
Шаг 3: Войдите в проект и запустите сервис
cd react123 && npm start
Через три вышеуказанных шага браузер автоматически откроется для доступа кlocalhost:3000(По умолчанию используется порт 3000) страницы React.
Теперь давайте посмотрим, как выглядит построенная структура, войдя в созданный реактивный проект.
Здесь, чтобы показать вам кое-что:
В соответствии с кружком, показанным на картинке выше, index.html в публичном каталоге представляет собой основной статический файл проекта (включая зависимые узлы), открыв его, вы найдете много контента, который на самом деле может быть удален. , вам нужно только оставить корень.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
После PUBLIC, поговорим о директории src, этот файл можно удалить (кромеindex.jsГлавный входной документ), а здесь webpack4 в сравнении файлов по умолчанию аналогично входу
Давайте сначала разберемся с jsx
В index.js под src мы можем начать путешествие React, React в основном разработан самим Facebook.jsxГрамматика, это набор js и xml, прямо по коду
// 首先引入react的核心包
// 这里的命名必须叫React,如果不是的话会报错
import React from 'react';
// 这里主要用到render方法,所以直接将其解构出来使用
import { render } from 'react-dom';
// jsx语法通过babel来转义,通过预设的babel-preset-react来进行转义
// 将jsx语法解析成js来使用
let ele = (
<h1 className="big">
hi, <span>baby</span>
</h1>
);
Мы можем поместить написанный синтаксис jsx непосредственно вофициальный сайт бабельанализировать
// 解析后的代码如下
React.createElement(
"h1",
{ className: "big" },
"hi, ",
React.createElement(
"span",
null,
"baby"
)
);
Создайте его с помощью React.createElementвиртуальный DOM, который содержит три параметра, которыетип, реквизит и дети
- тип: соответствующая метка h1
- реквизит: соответствующие свойства { className: "big" }
- дочерние элементы: соответствующие дочерние узлы -> строка «привет» и новый React.createElement( "охватывать", нулевой, "детка" )
На самом деле, по словам объекта, созданного реагированием .Createidelement, структура после печати подобна этому
Согласно структуре, напечатанной выше, на самом деле, они все экземпляры React.Element, поэтому давайте сделаем серьезную добычу для печатного объекта, чтобы увидеть, что является священным.{
type: 'h1',
props: {
children: [
'hi',
{
type: 'span',
props: {
children: 'baby'
}
}
],
className: 'big'
}
}
После преобразования объекта мы можем визуализировать такой объект с помощью метода рендеринга, предоставленного ReactDOM, и, наконец, отобразить его на странице.
Написанный выше блок кода ele на самом деле является React.createElement.синтаксический сахар, в конце концов, каждый раз, когда вы пишете такую большую партию React.createElement, происходит девять ошибок из десяти (я думаю, что это может быть 100% неправильно, ха-ха)
Итак, мы видим здесь, что можем просто разобраться со всем рендерингомисполнительный листохватывать
синтаксис jsx -> формат createElement -> преобразовать в объект -> преобразовать объект в реальный dom -> рендеринг метода рендеринга
import React from 'react';
import { render } from 'react-dom';
// React.createElement的语法糖
let ele = (
<h1 className="big">
hi, <span>baby</span>
</h1>
);
render(ele, window.root); // 将ele渲染到root上
На следующем рисунке показана ситуация, когда виртуальный дом отображается под корневым узлом.
Разница между написанием jsx и html
- className он будет преобразован в класс
- htmlFor его необходимо преобразовать в метку атрибута для
- элементы jsx могут быть вложенными
- Соседние элементы реакции должны быть обернуты слоем
- jsx, который может писать js, {} который может быть написан оператором js
- Поддерживает только многострочные комментарии, {/ * ... * /}, но редко пишет комментарии
- Тег стиля должен быть записан как объект, например: { background: 'skyblue' }
Поговорив об этих различиях, я могу начать прямо, нет более интуитивно понятного кода, чтобы любить, поторопись, иди, иди, иди
import React from 'react';
import { render } from 'react-dom';
// 提示:下面注释标记的数字对应上面区别的序号,序号5和6就不写了
let singer = '周杰伦';
let style = { backgroundColor: '#0cc', color: '#fff', fontSize: '14px' };
let album = '跨时代';
let arr = ['晴天', '阴天', '下雨天'];
let ele = (
/* 4.相邻的react元素外层必须包起来(h1,label,input,p它们都是相邻的),
vue是用一个template标签包起来,
可以写一个div包起来,不过会产生一个多余的div标签
react直接采用React.Fragment来包裹最佳
*/
<React.Fragment>
{ /*1.渲染后会转成<h1 class="song">烟花易冷</h1>*/ }
<h1 className="song">
烟花易冷-
{/* 3.jsx元素可以嵌套 */}
<span>{singer}</span>
</h1>
{/* 2.htmlFor会转成<label for="inp"></label>
点击label标签会自动获取到input焦点 */}
<label htmlFor="inp">获得焦点</label>
<input type="text" id="inp" />
{/* 7.style必须是对象的形式,如style={{color: '#fff'}} */}
<p style={style}>{album}</p>
{arr.map((item, index) =>{
return <li key={index}>{item}</li>
})}
</React.Fragment>
);
render(ele, window.root);
По приведённому выше коду можно интуитивно увидеть некоторые специфические отличия, так что если не получается есть вонючий тофу на скорую руку, продолжим писать. Это не две кисти реакции, ниже компоненты реакции!
компоненты
В реакции есть два типа компонентов, один из нихфункциональный компонент, одинкомпонент класса, то как отличить компонент ли это? Здесь есть стандарт, первая буква должна быть заглавной
какие? Да, верно, строчная - это элемент jsx, ха-ха, если не верите, посмотрите
функциональный компонент
import React from 'react';
import { render } from 'react-dom';
// 此为函数组件
function Song(props) {
return (
<div className="wrap">
<h1>晴天-{props.singer}</h1>
<p>为你翘课的那一天,花落的那一天</p>
<p>教室的哪一间,我怎么看不见</p>
</div>
);
}
// 组件可以通过属性传递数据
// render方法不会一直渲染,只会渲染一次
render(<Song singer="周杰伦" />, window.root)
Конечно, некоторые люди могут не поверить, но если я напишу песню как песню, а затем обработаю ее, что может быть не так?
На самом деле, нет никакой проблемы, это невозможно, потому что React знает вас и выдаст вам ошибку, говорящую вам, что если вы хотите использовать компонент React для рендеринга, то сделайте первую букву заглавной.
Чиновник сказал, старик не обманут, ха-ха
Продолжая возвращаться к обсуждению функциональных компонентов, функциональные компоненты — это три продукта без этого, без жизненного цикла и без состояния. Так что можно предположить, что частота использования не так хороша, как у классовых компонентов.
Возьмите каштан:
import React from 'react';
import { render } from 'react-dom';
// 函数组件Clock
function Clock(props) {
return <p>{props.date}</p>
}
setInterval(() => {
render(<Clock date={new Date().toLocaleString()} />, window.root);
}, 1000);
Время может обновляться в режиме реального времени, но, поскольку функциональный компонент не имеет состояния и будет отображаться только один раз, добавление таймера setInterval во внешний слой немного неуместно.
Что еще более важно, изменения состояния передаются нами через атрибуты.Без собственного состояния мы полагаемся на передачу при обновлении, что очень плохо.Особенность компонентов - повторное использование.
Поэтому мы торжественно пригласим Биг Мак в компонент, и дебютирует класс компонент.
компонент класса
Или вышеперечисленные каштаны, мы изменили форму классов компонентов
// 由于类组件需要继承react的Component,所以直接解构出来使用
import React, { Component } from 'react';
import { render } from 'react-dom';
class Clock extends Component { // 继承Component
constructor() {
super(); // 继承后可以使用setState方法
// 设置组件的默认状态
this.state = { date: new Date().toLocaleString(), pos: '北京' }
}
// 需要提供一个render方法返回dom对象
render() {
return (
<React.Fragment>
<p>当前时间:{this.state.date}</p>
<p>坐标:
<span style={{color: 'skyblue'}}>{this.state.pos}</span>
</p>
</React.Fragment>
);
}
// 一不小心就展示了目前的第一个生命周期了
// componentDidMount生命周期
// 当组件渲染完成后调用此生命周期
componentDidMount() {
setInterval(() => {
// 重新设置date的状态值,
// this.setState可以更改状态刷新页面
this.setState({date: new Date().toLocaleString()});
}, 1000);
}
}
render(<Clock />, window.root);
Тот же эффект достигается с помощью компонента класса выше, что нам не хватает дальше? мероприятие? Правильно, как можно написать js без добавления событий, поговорим о том, как добавлять события
Затем приведенный выше код продолжаем писать, набираем снова, не боясь устать, практика делает совершенным, это победа
import React, { Component } from 'react';
import ReactDOM, { render } from 'react-dom';
class Clock extends Component {
constructor() {
super();
this.state = { date: new Date().toLocaleString(), pos: '北京' };
// 强制绑定this
this.handleClick = this.handleClick.bind(this);
}
/* 绑定方法有几种方式 方法中可能会用到this
1.箭头函数 (不提倡,会产生个新函数,楼下2层也是)
2.bind绑定 this.handleClick.bind(this)
3.在构造函数中绑定this (官方推荐)
4.ES7语法可以解决this指向 handleClick = () => {} (更推荐,哈哈)
*/
handleClick = () => {
console.log(this) // 直接绑给一个函数的话,此时的this是undefined
// 在方法里,我们来移除一下这个组件
// 移除组件我们就用到了ReactDOM的方法
ReactDOM.unmountComponentAtNode(window.root);
}
render() {
// 这里绑定个click事件,用的是驼峰写法onClick
// 后面要跟js语法,onClick={}
return (<React.Fragment>
<p onClick={this.handleClick}>当前时间:{this.state.date}</p>
<p>坐标:
<span style={{color: 'skyblue'}}>{this.state.pos}</span>
</p>
</React.Fragment>)
}
componentDidMount() {
this.timer = setInterval(() => {
this.setState({ date: new Date().toLocaleString() });
}, 1000);
}
componentWillUnmount() {
clearInterval(this.timer);
}
}
render(<Clock />, window.root);
После выполнения приведенного выше кода, после нажатия тега p текущего времени, компонент (дом) будет удален из-под корневого узла, но некоторые распространенные проблемы могут быть проигнорированы, поэтому позвольте мне объяснить
- Когда вы нажимаете, чтобы удалить компонент, таймер все еще выполняется, а setState все еще обновляет состояние даты, поэтому будет ошибка
- Нижеследующее посвящено объяснению этого вопроса.
class Clock extends Component {
// 主要看这里(气质)
componentDidMount() {
// 和以往清除定时器的做法一样,我们直接将timer挂到this实例上
this.timer = setInterval(() => {
this.setState({date: new Date().toLocaleString()})
});
}
// 这个生命周期是组件将要被卸载的时候调用
componentWillUnmount() {
// 一般卸载组件后要移除定时器和绑定的方法
clearInterval(this.timer);
}
}
Ну, вышеуказанная проблема ошибки решается так. Однако лучше сказать, чем петь, зачем поставить таймера на это? Разве вы не можете положить состояние таймера в этом.
Помещение его в this.state означает, что текущая страница зависит от этого состояния, представление может обновляться при изменении состояния, а страница может обновляться с помощью setState.
Однако поместите таймер непосредственно на текущий экземпляр (это), немедленно удалите его (пустой), и это не повлияет на страницу.
Компоненты так много сказали, давайте подведем итоги.
- Компонент имеет два источника данных
- Один из них — это атрибут, переданный извне.
- Один - это государство, принадлежащее самому себе
Резюме окончено, выпьем стакан воды и продолжим смотреть вниз.Обнаруживаем, что состояние реакции очень важно.После изменения состояния можно обновить вид. Так легко повесить трубку, поэтому давайте поговорим только об этом состоянии.
государственный статус
Бледный текст не так захватывающий, как настоящий код, перейдите к коду
// 这是一个很常见很常见的栗子,计数器
import React, { Component } from 'react';
import { render } from 'react-dom';
class Counter extends Component {
constructor() {
super();
this.state = { count: 1 };
}
handleClick = () => {
// 写到这里就可以实现点击一次button就加1一次了
// this.setState({ count: this.state.count + 1 });
// this.setState也可以接受一个函数,它的第一个参数就是上一次的状态
//
this.setState(prevState => ({ count: prevState.count + 1 }));
this.setState(prevState => ({ count: prevState.count + 1 }));
this.setState(prevState => ({ count: prevState.count + 1 }));
}
render() {
return (
<div>
<span>计数器: </span>
{this.state.count}
<button onClick={this.handleClick}>点我</button>
</div>
);
}
}
render(<Counter></Counter>, window.root);
У состояния есть особенность: можно ли обновлять несколько состояний пакетами? То есть, если я напишу три this.setState для изменения счетчика, то по здравому смыслу состояние должно измениться три раза, а кнопка увеличится на 3 один раз
На самом деле React этого делать не будет.Если состояние изменится один раз и страница обновится один раз, это будет сумасшествие.React сначала запоминает состояние (количество), а затем обновляет страницу вместе в конце.
Поэтому я использую приведенный выше сброс setState, чтобы сохранить состояние счетчика и, наконец, изменить его все сразу. Грубо говоря, если следующее состояние обновления зависит от предыдущего состояния, оно должно быть записано в виде функции
Ну, здесь приезжают, чтобы поговорить о связи между компонентами этого, сначала до прямых родительских компонентов связи.
Связь между компонентами
Связь между компонентами, между отцом и сборкой передается через свойство, родитель -> дочерний -> внуки
Односторонний поток данных, направление данных одностороннее, дочерний элемент не может изменять атрибуты родителя Давайте посмотрим на небольшую демонстрацию
Родительский компонент song.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import axios from 'axios'; // axios用于请求
import List from './list'; // 子组件
import Audio from './audio'; // 子组件
import './css/songs.css';
class Songs extends Component {
constructor() {
super();
this.state = { songs: [], mp3Url: '', isPlay: false };
}
// 子传父通信 -> 父提供一个方法,子调用后将参数回传
// chooseSong为选择歌曲地址填入audio的src的方法
chooseSong = (url, isPlay) => {
// 这里子组件回传了属性更改了isPlay的状态
// 对应修改了List的同级组件Audio接收的played属性值
this.setState({mp3Url: url, isPlay});
}
render() {
return (
<div className="songs-box">
<ul>
{this.state.songs.map((item, index) => (
/*
通过传递属性的方式进行通信
这里将item解构出来,然后List子组件按照需要去拿数据
*/
<List key={index} {...item} choose={this.chooseSong}></List>
))}
</ul>
<Audio url={this.state.mp3Url} played={this.state.isPlay}></Audio>
</div>
);
}
async componentDidMount() {
// 在react中发送ajax请求 现在我们用axios
// axios封装了RESTFul 基于promise的 不支持jsonp 可用在服务端
let { data } = await axios.get('http://musicapi.leanapp.cn/search?keywords=林俊杰');
this.setState({ songs: data.result.songs });
}
}
render(<Songs></Songs>, window.root);
нет эффекта
Эффект воспроизведенияЯ не буду показывать весь остальной код один за другим, это всего лишь простое демо, многие функции не идеальны, заинтересованные студенты могут его изучить и продолжить писать.опубликовать адресВ приведенной выше небольшой демонстрации можно обнаружить, что существует три основных способа связи между компонентами.
- Первый способ - пройти через атрибуты, родитель -> дочерний -> внук (от отца к ребенку)
- Односторонний поток данных, направление данных одностороннее, дочерний элемент не может изменять атрибуты родителя
- Второй способ — родитель написал метод и передал его сыну (сын передает отцу)
- Сын вызывает этот метод, в этом методе можно изменить состояние
- Третий способ - симпатия того же уровня
- Если одноуровневые компоненты хотят передать данные, они могут найти общего родителя и создать родителя без родителя.
Контролируемые и неконтролируемые компоненты
Далее давайте рассмотрим две концепции контролируемых компонентов и неконтролируемых компонентов, которые относятся к элементам формы.
Поскольку задействованы элементы формы, ожидаемая двусторонняя привязка данных также должна появиться.
двусторонняя привязка данных
import React, { Component } from 'react';
import { render } from 'react-dom';
class Input extends Component{
constructor(){
super();
this.state = {val: '你好'};
}
// 通过onChange事件调用该方法后,每次更改输入后val的状态值
handleChange = (e) =>{ //e是事件源
let val = e.target.value;
this.setState({val});
};
render(){
return (<div>
<input type="text" value={this.state.val} onChange={this.handleChange}/>
{this.state.val}
</div>)
}
}
render(<Input />, window.root);
Двусторонняя привязка данных осуществляется в основном путем отслеживания события onChange, а затем каждый раз изменяя новое значение входного значения на состояние соответствующего val, а затем присваивая его атрибуту value входа, реализуя реализацию двустороннего передача данных, которая действительно продвинута, ха-ха
Управляемые компоненты
Управляется сборкой состояний, должен быть метод onChange, иначе нельзя использовать
Управляемым компонентам могут быть присвоены значения по умолчанию
import React, { Component } from 'react';
import { render } from 'react-dom';
class App extends Component{
constructor(){
super();
this.state = {a: '破风', b: '激战'};
}
// name表示的就是当前状态改的是哪一个
// e表示的是事件源
handleChange = (e) => { //处理多个输入框的值映射到状态的方法
let name = e.target.name;
this.setState({ [name]: e.target.value });
}
render(){
return (
<form>
<input type="text"
required={true}
value={this.state.a}
onChange={this.handleChange}
name="a"
/>
<input type="text"
required={true}
value={this.state.b}
onChange={this.handleChange}
name="b"
/>
<input type="submit" />
<p>{this.state.a}</p>
<p>{this.state.b}</p>
</form>
)
}
}
render(<App></App>, window.root);
Наконец, взглянем на неуправляемые компоненты
неконтролируемые компоненты
Так называемые неконтролируемые компоненты имеют три характеристики:
- Может управлять домом, получить настоящий дом
- Можно комбинировать со сторонними библиотеками
- Нет необходимости проверять текущее входное содержимое, и не требуется значение по умолчанию.
import React, { Component } from 'react';
import { render } from 'react-dom';
// 1.函数的方式 ref
// 2.React.createRef() v16.3+
class App extends Component {
constructor() {
super();
this.aaa = React.createRef();
}
componentDidMount() {
// this.aaa.focus(); // 对应1
this.aaa.current.focus(); // 对应2
}
render() {
return (<div>
{/* 1.<input type="text" ref={input=>this.aaa = input} />*/}
{/* 2.会自动的将当前输入框 放在this.aaa.current */}
<input type="text" ref={this.aaa} />
</div>)
}
}
render(<App />, window.root);
Что касается каштана выше, он автоматически получит фокус поля ввода, как только вы войдете на страницу, после чего вы можете попробовать коснуться его.
Еще не рано, шоу в самый раз
Хотя в React еще есть о чем поговорить, и он еще не охватил жизненный цикл и так далее.
Однако не волнуйтесь, все, кто должен прийти, всегда придут, и никого из них нельзя пропустить.В следующих статьях я продолжу учиться и делиться.
Итак, на сегодня все, спасибо всем за просмотр, всем, Энн! ! !