Краткое знакомство с React методом грубой силы

внешний интерфейс React.js
Краткое знакомство с React методом грубой силы

Краткое знакомство с React методом грубой силы

На сегодняшний день React является одним из трех основных фреймворков.После краткосрочного изучения я сделал несколько заметок и поделился ими: Если есть какие-то ошибки, пожалуйста, укажите на них.

1. Введение в React

1. Что такое Реакт:

ReactэтоFacebookразработан для создания пользовательского интерфейсаJavascriptбиблиотека.
Reactа такжеVueв сравнении с,vueСинтаксис прост и удобен в использовании, подходит для небольших, но сложных проектов, ноReactПовторное использование и дизайн компонентов будут лучше, чемvueОдин чип, подходящий для масштабных проектов.
ReactРазделяйте и собирайте страницы на компоненты одну за другой и повторно используйте их для повышения эффективности (см. рисунок ниже)ReactОбработка и управление данными понятнее, чем нативные.

2. Возможности React

  1. Декларативный дизайн− Каждый компонент React создается путем объявления, что делает логику страницы более понятной.

582_1.png 2. виртуальный DOM− React создает виртуальную DOM каждый раз, когда отображает страницу, сравнивает ее с существующей DOM, а также заменяет и повторно отображает те, которые отличаются, что повышает эффективность.584_1.png 3. JSXJSXдаJavaScriptРасширение синтаксиса.ReactРазработка не обязательно используетJSX, но мы рекомендуем его использовать.

// 在 javascript中创建元素
const DOM = document.createElement("h1"); // 真实DOM
DOM.innerText = "这是h1标签";

// 在 jsx中创建元素
const VDOM = <h1>这是h1标签</h1> // 虚拟DOM
  1. компоненты− Создание компонентов с помощью React упрощает повторное использование кода и может хорошо использоваться при разработке крупных проектов.
// 不必现在就看懂,仅需要知道每个组件都是需要进行声明后才能使用
import React, {PureCompoent} from "react";
export default class Header extends PureCompoent{
    render(){
        return <header>这是头部组件</header>
    }
}
// ------------------------------------------------
// 在需要使用 header组件时调用即可重复使用
import Header from "./Header";
<Header></Header>
  1. Односторонний поток данных ответа− React реализует односторонний реагирующий поток данных, который уменьшает дублирование кода, поэтому он проще, чем традиционная привязка данных. (Это будет изучено позже)

3. Установка и использование

  1. использоватьcdn
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  1. Импортируйте пакет React, загрузив
<script src="../js/react.development.js"></script>
<script src="../js/react-dom.development.js"></script>
<script src="../js/babel.min.js"></script>
  1. Использование реагирующих лесовcreate-react-appСоздание файла проекта будет сопровождаться реакцией
npm i create-react-app -g
create-react-app 项目名称

Примечание: используйтеreactдолжен использоватьbabel.jsБудуjsxсинтаксис для jsграмматикаReactDOMНезависимо отReact(предотвращатьReactСлишком большой и раздутый, чтобы разобрать)

4. Виртуальный дом

(1) О виртуальном DOM

Суть виртуального DOM — это объект, реальный DOM также является объектом, но виртуальный DOMМеньше свойств, больше легкости.

// 虚拟DOM  
const VDOM = <h1>Hello World</h1>; // 此处不需要引号,因为不是字符串
// 真实DOM
const TDOM = document.querySelector("#app");

console.log("虚拟DOM: ", VDOM);   // Object
console.log("真实DOM: ", TDOM);   // <div id="app"></div>
console.log("虚拟DOM类型: ", typeof VDOM);  // object
console.log("真实DOM类型: ", typeof TDOM);  // object
console.log(VDOM instanceof Object);    // true
console.log(TDOM instanceof Object);    // true

Виртуальный DOM в конечном итоге будет преобразован в реальный DOM, чтобы быть на странице.

(2) Создайте виртуальный DOM

  1. пройти черезReactМетодыcreateElement()способ создания виртуального DOM
// React.createElement(标签名称, 标签属性, 标签内容)
const VDOM1 = React.createElement("h1", {id: "title"}, "This is Title");
  1. используя первый методсинтаксический сахарСоздать виртуальный DOM
const VDOM2 = <h1 id="title">This is Title</h1>;

5. ОJSX

jsxграмматика иjavascriptСинтаксис очень похож, только несколько предостережений

// 虚拟DOM  
const VDOM = (  // 使用括号框住 jsx标签表示层级会更加美观些。
    <h1>
        <span>Hello World</span>
    </h1>
)
const myid = "HeLlO";
const content = "Happy New Year"
const students = [
{id: "001", name: "Tom", age: 18},
{id: "002", name: "Tim", age: 19},
{id: "003", name: "Jerry", age: 20},
];
const VDOM2 = (
    <div>
        <h2 className="title" id={myid.toLowerCase()}>
            <span style={{color: 'pink'}}>{content}</span>
        </h2>
        <ul>{/* 使用 ES6的 map() 函数进行列表渲染(将数据批量渲染到页面上) */}
        {
            students.map(student=>{
                return <li key={student.id}>{student.name}---{student.age}</li>
            }
        }
        </ul>
        <input type="text"/>    
    </div>
)

Правила грамматики jsx:

  1. Не пишите кавычки при определении виртуального DOM
  2. Используйте при смешивании js-выражений в тегах{}
    • Выражение дает значение и может быть помещено в любое место, где требуется значение.
    • Оператор — это строка кода, используемая для обработки логики.
  3. Имя класса в теге указывает не использовать класс, используйте className
  4. При использовании встроенных стилей в тегах используйте двойные скобки (используйте маленький верблюжий регистр для написания стилей CSS).
  5. При добавлении свойств события (например,onclick),onДелайте заглавными первые буквы следующих слов (например,onClick)
  6. Виртуальный DOM должен иметь только один корневой тег
  7. Этикетка должна быть закрыта
  8. начало этикетки
    • Когда тег начинается с нижнего регистра, он будет скомпилирован в html-тег с помощью jsx.Если html не соответствует элементу с таким же именем, будет сообщено об ошибке
    • Когда метка начинается с прописной буквы, jsx распознает ее как компонент, если соответствующий компонент не найден, он будет

6. Рендеринг на страницу

использоватьReactDOMизrender()метод рендеринга

const VDOM = <h1 id="title">This is a Title</h1>;    // 创建虚拟DOM
// ReactDOM.render( 组件(虚拟DOM),  要绑定到哪个元素上 );
ReactDOM.render(VDOM, document.querySelector("#root"));

Во-вторых, использование компонентов

существуетReact, существует два способа создания компонентов, а именнофункциональные компонентыа такжекомпонент класса. вкомпонент классаВысокая частота использования (появился React 16.8HookЕсть и более постфункциональные компоненты)

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

Как следует из названия, этот компонент написан функцией

function Demo(props){    // 定义一个组件,名为 Demo
    return <h2>This is a component</h2>;    // 返回值为组件的DOM内容
}
ReactDOM.render(<Demo/>, document.querySelector("#root"))

Определение функционального компонента:

  • Имена функций должны быть написаны с заглавной буквы
  • При вызове он вызывается с меткой и начинается с верхнего регистра.
  • Параметры функционального компонента:props(будет обсуждаться позже)

компонент класса

Компонент построен с классами, но должен наследоватьReactкласс, который идет сComponent.

// 使用 ES6写法创建类式组件,并继承于 React.Component
class Demo extends React.Component{
    
    // 添加render() 函数(必须),返回值为组件的虚拟DOM
    render(){
        console.log(this);      // render() 函数的 this 指向组件的实例对象
        return <h1>This is a Title!</h1>
    }
}
ReactDOM.render(<Demo/>, document.querySelector("#root"));

Определение компонента класса:

  • должен унаследоватьReactвстроенный классComponent
  • метод должен быть включенrender()
  • Конструкторconstructor()Параметрыprops(будет описано позже), если вам нужно использоватьconstructorконструктор родительского класса должен быть вызванsuper(props)

Выполнение при монтировании компонента класса:

  1. ReactРазобрать тег компонента и найтиDemoкомпоненты
  2. найден как компонент класса, тоnewиз объекта экземпляра класса, вызвать объект-прототип через экземплярrenderметод
  3. Будуrenderметод возвращенвиртуальный DOMПеревести внастоящий ДОМ, который затем отображается на странице

Примечания к определениям компонентов:

  1. компонент классаrender()Метка возвращаемого компонента и метка компонента, возвращаемая функциональным компонентом, должны иметь одинкорневой тег
  2. должно бытьначинать с заглавной буквы

Монтаж и демонтаж компонентов

Маунтов я видел много, поэтому перехожу сразу к коду:

// ReactDOM.render( 组件, 要绑定在哪个元素上 );
ReactDOM.render( <Demo/>, document.querySelector("#app") );

Код удаления немного длиннее, и я написал его прямо:

// ReactDOM.unmountComponentAtNode( 要卸载哪个元素上的组件 );
ReactDOM.unmountComponentAtNode( document.querySelector("#app") );

Другие маленькие знания

  1. Компоненты, содержащие элементы формы, делятся набесконтрольная рентаа такжеУправляемые компоненты
    • Управляемые компоненты: Компонент ввода компонента формы хранит содержимое в состоянии с вводом (обновляется в любое время)
    • неконтролируемые компоненты: Содержимое компонента ввода компонента формы сохраняется в состоянии, когда оно требуется (готово к использованию)

Три, три свойства компонентов

Суть компонента — это объект, а у объекта, естественно, есть свойства.Три наиболее часто используемых свойства в компонентах:state,propsа такжеrefs

1. state

stateто есть компонентусловие, ясной точкой являются данные, хранящиеся (необходимые для использования) компонентом

Использование в компонентах класса:

class Weather extends React.Component{
    constructor(props){
        super(props);
        // this.state = {weather: "Spring"}     // 也可以在构造函数中定义 state
    }
    
    state = {   // 定义 state
        weather: "summer",
    }
    
    render(){
        // 当前季节为:summer
        return <h2>当前季节为:{ this.state.weather }</h2>
    }
}

когда используешьthis.stateпередачаstateзначение в определение компонента классаstate:

  • можно инициализировать в конструктореstate
  • Вы можете добавить свойства к классуstateинициализировать

Использование в функциональных компонентах

  • существуетReact16.8Ранее функциональные компоненты не могли иметь собственныхstate(поскольку данные будут инициализироваться повторно)
  • прибытьReact16.8После этого появилсяHookметод, так что функциональные компоненты также могут быть использованыstateОсобенности, вы можете сначала понять их, а потом научить им.
function Demo(){
    const [weather, setWeather] = React.useState("Winter");
    return <h2>当前季节为:{weather}</h2>     // 当前季节为:Winter
}

изменить состояние

существуеткомпонент классафункция, вы найдете прямую модификациюstateзначение, например:

this.state.count = 1

Если вы используете на страницеcountЭто значение, вы обнаружите, что эта страница не изменилась?
Разберитесь, от какой функции зависит рендеринг страницы? не зависеть отrender()функция?
Если вы изменяете напрямую каждый разstateПосле звонкаrender()Если это функция, не будет ли она казаться слишком громоздкой?
фактическиReactтакже не рекомендуетсяstateПрямая модификация не допускается, но черезконкретный каналмодифицировать, значит использовать вна объект-прототип классаМетодыsetState()

setState()
this.setState(partialState, [callback]);
  • partialState: Частичный объект состояния, который необходимо обновить.
  • callback: Функция обратного вызова после обновления состояния

setStateЕсть два способа написать: Запись 1:

this.setState({
    count: 1,
})

Написание 2:

// 传入一个函数,返回x需要修改成的对象,参数为当前的 state
this.setState(state => ({count: state.count+1});

Используйте это обозначение в зависимости отНужно ли применять измененное состояние к текущему состоянию

forceUpdate()

Другой способ изменить состояниеforceUpdate, значениеПринудительное обновление, то есть состояние принудительно обновляется.
Параметр является функцией обратного вызова после завершения обновления статуса.

this.forceUpdate([callback]);

setStateобновление сforceUpdateОбновление - это операция слияния, а не операция заменить


  • в исполненииsetStateПосле операции,Reactавтоматически поможет нам позвонить один разrender()
  • render()Количество казней1+n(1 — автоматический вызов при инициализации, n — количество обновлений состояния (т. е. вызовsetStateилиforceUpdateколичество раз))
  • Используйте экономно или нетforceUpdate

2. props

а такжеstateразные,stateэто состояние (данные) самого компонента, иpropsЭто состояние (данные), переданное самому себе извне

propsМодификация в компоненте, который должен быть передан тому, кто будет его изменять

используется в компонентах класса

class Person extends React.component{

    constructor(props){     // 还记得构造函数的参数吗,也能够获取 props
        super(props);
    }

    // 可以使用静态属性 propTyps 来限制props
    static propTypes = {
         // 在 16版本前,通过使用React自带的PropTypess属性传递值
        // name: React.PropTypes.string.isRequired,
        
        // 16版本后,PropTypes被单独移出 React作为单独的个体,需要另外导入
        name: PropTypes.string.isRequired, // 字符串类型,且必须传值
        sex: PropTypes.string,  // 字符串类型
        age: PropTypes.number,  // 数字类型
        speak: PropTypes.func,  // 函数类型
    }
    
    // 可以使用静态属性 defaultProps 来设置某些 prop 的默认值
    static defaultProps = {
        sex: "男",   // 设置 sex 的 prop 默认值为 “男”
    }

    render(){
        const {name, sex, age} = this.props;    // 从 props中获取值
        return (
            <ul>
                <li>姓名:{name}}</li>
                <li>性别:{sex}</li>
                <li>年龄:{age}</li>
            </ul>
        )
    }
}

// ReactDOM.render( <Person name="Tom" sex="男" age="16"/>, document.querySelector("#root"));    // 以类似属性的方式传递 props值

ReactDOM.render(<Person {...p} />, document.querySelector("#root"));  
// 可以用扩展运算符来传递 props值

можно использовать при использованииthis.propsчтобы получить значение компонент классаprops:

  1. Передав значение на метке компонента, вы можете получить переданное значение в компоненте
  2. Его можно получить в параметрах конструктораprops
  3. можно установить отдельноpropTypesа такжеdefaultPropsдва свойства работать отдельноpropsспецификация и значения по умолчанию, оба из которых добавляются непосредственно в компонент классапрототип объектана (поэтому нужно добавитьstatic)

Использование в функциональных компонентах

Помните, что вы говорили о параметрах функционального компонента? являетсяprops.
Метод передачи такой же, как и у компонента класса, который заключается в передаче значения в теге компонента.

function Person(props){   // 参数为 props
    const {name, sex, age} = props;     // 使用占位符获取 props的值
    return (
        <ul>
            <li>姓名:{name}}</li>
            <li>性别:{sex}</li>
            <li>年龄:{age}</li>
        </ul>
    )
}

Person.defaultProps = {     // 设置 props默认值
    sex: "男",
    age: 18,
}
Person.propTypes = {    // 设置 props限制
    name: PropTypes.string.isRequired,
    sex: PropTypes.string,
    age: PropTypes.number,
}

const p = {name:"Jerry", sex:"女", age:16}
ReactDOM.render(<Person {...p}/>,document.querySelector("#app"));

функциональный компонентpropsопределение:

  1. То же самое также передается в теге компонентаpropsзначение
  2. Параметры функции компонента:props
  3. правильноpropsОграничения и установка значений по умолчанию также находятся на объекте-прототипе.

3. refs

Предположим, у вас есть элемент формы в вашем компоненте, а затем вам нужно получить в нем значение, как его получить? Некоторые люди могут захотеть связать элементidпосле использованияdocument.querySelectorнайти элемент, но это нарушаетReactИдея снова начать манипулировать элементами DOM, всеReactпредоставляет третью функциюrefs

существуетReactВ истории есть три операцииrefsметоды соответственно:

  • Строковая форма
  • форма обратного звонка
  • createRefформа

Давайте рассмотрим их один за другим:

используется в компонентах классаrefs

(1) в виде строкиrefs
class Demo extends React.Component{
    
    showData(){
         // 通过自己设定的 refs名称获取对应的元素
        const {myInput} = this.refs;   // 返回该元素
        alert(myInput.value)
    }
    
    render(){
        return (
            <div>
                { /* 通过 ref属性绑定这个 input标签 */ }
                <input type="text" ref="myInput" placeholder="search something" />
                {/* 事件绑定会在下面讲 */}
                <button onClick={this.showData}>Show Data</button>
            </div>
        )
    }
}
(2) В форме обратного вызоваrefs

Это на самом деле очень просто, но в более поздних версиях официалы посчитали, что с этим проблема, поэтому была запущена новая версия: использование callback-функций для работыrefs

class Demo extends React.Component{
    
    showData(){
        const {myInput} = this;   // 返回该元素
        alert(myInput.value)
    }
    render(){
        return (
            <div>
                {/* 回调函数的参数为该元素本身,通过函数绑定在 this上 */}
                <input type="text" ref={ e => this.myInput = e } placeholder="search something" />
                <button onClick={this.showData}>Show Data</button>
            </div>
        )
    }
}
(3) форма createRef (рекомендуется)

позжеReactВыявлено, что есть еще какие-то невыразимые проблемы в виде использования callback-функции, поэтому в очередной раз вводится новый метод использованияrefs, это использоватьReactметод телаcreateRef()

class Demo extends React.Component{

    // 使用 React.createRef() 创建一个 ref容器
    myRef = React.createRef();

    showData = ()=>{
        // 在容器中获取 DOM元素
        const {current} = this.myRef;
        alter(current.value);
    }

    render(){
        return (
            <div>
                {/* 将DOM元素绑定在容器中 */}
                <input ref={this.myRef} placeholder="点击提示数据" type="text"/>
                <button onClick={this.showData}>ShowData</button>    
            </div>
        )
    }
}

Примечание: аrefКонтейнер, может хранить только один элемент (только специалист), и тот, который будет добавлен позже, вытеснит предыдущий.

Использование в функциональных компонентахrefs

  • существуетReact16.8раньше, сstateТочно так же нельзя использовать функциональные компонентыrefsхарактеристика
  • существуетReact16.8После этого появилсяHookфункции, что делает функциональные компоненты также доступнымиrefsспособность охарактеризовать

Следующий код не нужно понимать на данном этапе, просто поймите его.

function Demo() {
    const [count, setCount] = React.useState(0);
    function add(){
        setCount(count=> count+1);
    }
    return (
        <div>
            <h2>当前求和:{count}</h2>
            <button onClick={add}>点击加一</button>
        </div>
    )
}

В-четвертых, привязка событий компонентов

1. Привязка событий в функциональных компонентах

Вы можете определить другую функцию (встроенную функцию) в функции и вызвать ее

function Demo(props){
    function showData(){
        console.log(props);
        alert("触发了事件");
    }
    return (
        <div>
            <button onClick={showData}>点击触发</button>
        </div>
    )
}

2. Привязка событий в компонентах класса

В компоненте класса его можно вызвать через метод самого класса

class Demo extends React.Component{
    state = { count: 0 }    // 定义 state
    showData(){
        alert("触发了事件")
        console.log(this.state.count);; 报错
    }
    render(){
        return (
            <div>
                <button onClick={this.showData}></button>
            </div>
        )
        // 成功弹出弹窗,但是输出报错
    }
}

Здесь вы обнаружите, что хотя успехalter, но выводstateОн сообщит об ошибке, почему это?

Обычно используется в компонентахthis.stateкогда, в это времяthisВсе указатели действуют на класспрототип объекта, сам класс.
А в функции, потому что с помощьюbabel.jsво имяjsвключено по умолчаниюстрогий режим, Итак, тело функцииthisдляundefined, естественно не найденный на объекте-прототипеstate.
На данный момент есть два обходных пути:

  • использоватьbind,applyи другие методы измененияthisнаправление
  • использоватьстрелочная функция,ИзменятьthisУкажите (рекомендуется)
class Demo extends React.Component{
    constractor(props){
        super(props);
        // this.showData = this.showData.bind(this);   // 方法1
    }
    
    state = { count: 0 }    // 定义 state
    showData = ()=>{    // 方法2
        alert("触发了事件")
        console.log(this.state.count);; 报错
    }
    render(){
        return (
            <div>
                <button onClick={this.showData}></button>
            </div>
        )
        // 成功弹出弹窗,但是输出报错
    }
}

3. Метод обработки событий React

  • пройти черезonXxxСвойство указывает функцию обработчика событий (обратите внимание на случай
    • ReactиспользуетПользовательские (синтетические) события, вместо нативных событий DOM (для лучшей совместимости)

    • ReactСобытие обрабатывается делегированием события (делегируется самому внешнему элементу компонента) (для большей эффективности)

    • через событиеevent.targetПолучить полученный объект элемента DOM, который можно свернутьrefsиспользование

    • при привязке событийне добавляйте скобки, которые будутjsxОпределено как выполняющая функция

    • Примечание о функциях привязки в компонентах классаthisСуть проблемы (используются рекомендуемые связанные функциистрелочная функция)

Пять, жизненный цикл компонентов

правильноVueЗнакомый должен быть правЖизненный циклНе незнакомый.
В процессе монтирования компонента на страницу происходит много всего, и жизненный цикл можно рассматривать какПоток выполнения компонента, мы можем что-то сделать, выполнив что-то в узле процесса, и этоКрючки жизненного цикла (функции)
Примечание. Функции жизненного цикла применимы только к компонентам класса, а не к функциональным компонентам, а вReact16.8ПослеHook, вы также можете заставить функциональные компоненты реализовывать функции, аналогичные хукам жизненного цикла.

1. До реакции 16

592_1.png

Вот поток:

  • собственное крепление компонентов
    1. constructor: конструктор (инициализация)
    2. componentWillMount: Перед установкой компонента
    3. render: компонент монтируется
    4. componentDidMount: после того, как компонент смонтирован
  • Имеет родительский компонент, и состояние родительского компонента обновляется (setState):
    1. родительский компонентshouldComponentUpdate: выполняет ли родительский компонент обновление состояния
    2. родительский компонентcomponentWillUpdate: Перед обновлением состояния родительского компонента
    3. родительский компонентrender: Родительский компонент обновляется и монтируется
    4. ПодсборкаcomponentWillReceiveProps: дочерний компонент получит новыйProps
    5. ПодсборкаshouldComponentUpdate: выполняет ли дочерний компонент обновление состояния
    6. ПодсборкаcomponentWillUpdate: Перед обновлением состояния дочернего компонента
    7. Подсборкаrender: Подкомпонент обновляется и монтируется
    8. ПодсборкаcomponentDidMount: Монтаж подкомпонента завершен
    9. родительский компонентcomponentDidMount: Родительский компонент монтируется
  • Когда компонент нужно удалить:
    1. componentWillUnmount: Перед удалением компонента

Есть несколько замечаний:

  • shouldComponentUpdateозначает, обновлять ли состояние, поэтому он должен иметьлогическийвведите возвращаемое значение и по умолчаниюtrue(Если вы его не пишете), не забудьте написать возвращаемое значение, когда вы пишете этот хук.Этот горизонтальный цикл бровей обычно используется, чтобы сделать некоторые суждения о значении обновления.
  • shouldComponentUpdateЕсть два параметра, которыеnextProps:новыйpropsа такжеnextState: новыйstate, ни один из них не был обновлен до этого компонента.
  • использоватьsetStateжизненный циклshouldComponentUpdate, но используяforceUpdateнет, а непосредственноcomponentWillUpdateЖизненный цикл

2. После реакции 16

594_1.png

Сравнение старого и нового жизненного цикла:

  1. В новом жизненном цикле отбрасываются (отбрасываются) три функции жизненного цикла:
    • componentWillMount
    • componentWillReceiveProps
    • componentWillUpdate
  2. Добавлены две новые функции жизненного цикла:
    • getDerivedStateFromProps

    • getSnapshotBeforeUpdate

Вот поток:

  • Смонтировать собственные компоненты:
    1. constructor: конструктор (инициализация)
    2. getDerivedStateFromProps: отpropsполученный изstate
    3. render: компонент монтируется
    4. componentDidMount: компонент смонтирован
  • Когда родительский компонент обновляется
    1. родительский компонентgetDerivedStateFromProps: отpropsполученный изstate
    2. родительский компонентshouldComponentUpdate: определить, следует ли обновлять статус
    3. родительский компонентrender: родительский компонент монтируется
    4. ПодсборкаgetDerivedStateFromProps: отpropsполученный изstate
    5. ПодсборкаshouldComponentUpdate: определить, следует ли обновлять статус
    6. Подсборкаrender: Подкомпонент монтируется
    7. ПодсборкаgetSnapshotBeforeUpdate: дочерний компонент получает моментальный снимок перед обновлением состояния.
    8. ПодсборкаcomponentDidUpdate: Подкомпонент завершает обновление
    9. родительский компонентgetSnapshotBeforeUpdate: родительский компонент получает моментальный снимок перед обновлением состояния.
    10. родительский компонентcomponentDidUpdate: Родительский компонент завершил обновление
  • Когда компонент удален
    1. componentWillUnmount: Перед удалением компонента

Также следует отметить несколько моментов:

  • getDerivedStateFromPropsНеобходимо определить сам экземпляр, поэтому это статический метод.
  • getDerivedStateFromPropsЕсть два параметра, которые являются текущимиpropsа такжеstate
  • Если состояние компонента требуется в любой момент в зависимости отpropsтогда вы можете использоватьgetDerivedStateFromProps, но сценарии использования встречаются реже и могут быть определены вstate
  • getSnapshotBeforeUpdateТам два параметра соответственно перед обновлением состоянияpropsа такжеstate, и имеет возвращаемое значение (моментальный снимок), которое обычно используется в качестве описания ситуации обновления.
  • componentDidUpdateЕсть три параметра соответственно перед обновлением состоянияpropsа такжеstate, а ранееgetSnapshotBeforeUpdateСнапшот вернулся.
  • Другие ничем не отличаются от старого жизненного цикла

Шесть, рендеринг списка компонентов, условный рендеринг и DOM.Diffingалгоритм

1. Рендеринг списка компонентов

Иногда нам нужно создать на странице некоторые элементы или компоненты DOM в пакетном режиме, например: список новостей, список твитов, список друзей и т. д. Вы обнаружите, что списки часто используются в процессе разработки, но вы можете использовать их один раз. по одному Очень громоздко записывать DOM обратно.
Мы можем хранить данные через массивы или использовать массивы для рендеринга данных в цикле.
Например:

class Demo extends React.Component{
    state = {
        arr: [a, b, c],
    }
    render(){
        // 输出 abc
        return (
            <div>
                <ul> {stus} </ul>
            </div>
        )
    }
}

ты найдешь,ReactВыходной массив будет зацикливать все элементы напрямую, поэтому нам нужно только добавить метки слева и справа от каждого элемента, разве это не представляет собой рендеринг списка?
Здесь мы можемjsxсинтаксическая координацияES6оператор для реализации рендеринга списка.
Перейдите непосредственно к коду:

class Demo extends React.Component{
    state = {
        stus: [
            {id: "001", name: "小明", age: "28"},
            {id: "002", name: "小红", age: "26"},
        ],
    }
    render(){
        return (
            <div>
                <ul>
                    {
                        this.state.stus.map(item =>{
                            return <li key={item.id}>{item.name}---{item.age}</li>
                        })
                    }
                </ul>
            </div>
        )
    }
}

598_1.png

2. Использование ключей

Некоторые люди считают, что при написании рендеринга списка я добавляю тег к каждому тегу.keyсвойство, почему это?
фактическиkeyРоль состоит в том, чтобы добавитьуникальный идентификатор, для дачиReactпровестиалгоритм сравненияиспользуется при расчете

3. Дифференциация алгоритма

Когда состояние изменится, реакция сгенерирует [новый виртуальный DOM] в соответствии с [новым состоянием].
Затем сравните новый и старый виртуальный DOM по diff, правила сравнения следующие:

  1. В старом виртуальном DOMнашел этотот же ключ, что и новый виртуальный DOM
    • Если содержимое виртуального DOM не изменилось, используйте предыдущий реальный DOM напрямую.
    • Если содержимое виртуального DOM изменяется, создается и заменяется новый реальный DOM.
  2. В старом виртуальном DOMне найденС тем же ключом, что и новый виртуальный DOM, новый реальный DOM создается на основе данных, а затем отображается на странице.

Возможные проблемы с индексом в качестве ключа

  • Добавляйте и удаляйте данные в обратном порядке и нарушайте порядок операций Будет генерировать ненужные реальные обновления DOM, влияющие на эффективность
  • На DOM с входным классом в структуре Будет производиться неправильное обновление DOM и проблемы с отрисовкой интерфейса.
  • Если он используется только для отображения данных, нет проблем с индексом в качестве ключа.

7. Реагировать на строительные леса

Поздравляю, я наконец-то добрался до строительных лесов и наконец-то могу генерировать все одним щелчком мыши, а не ссылаться на них по одному.
Что такое строительные леса? Можно сказать, что строительные леса являются структурой при строительстве дома.Другие уже установили структуру дома для вас, поэтому вам не нужно делать это самостоятельно.
а такжеReactУ него есть свои строительные леса, и команда разработчиков проходитwebpack,babel,npmи другие методы, которые помогут вам построить использованиеReactСреда для разработки программного обеспечения, вам больше не нужно самостоятельно создавать папки, импортироватьReactи другие повторяющиеся операции, нам удобнее писатьSPAПриложение (одностраничное многофункциональное приложение).

1. Установите леса React

Введите в своем собственном окне командной строки (требуется существующийnodeокружающая обстановка):

npm i create-react-app -g

Установить глобальноcreate-react-appстроительные леса

2. Создайте приложение React

create-create-app 应用名称
  • В названии приложения не должно быть заглавных букв и специальных символов.
  • Используйте английские имена вместо китайских имен

3. Разбор файлов

В файлах проекта чаще всего используются следующие файлы:

  • node_modules------ Где хранится пакет npm
  • public------ Используется для хранения статических файлов
  • src------ Место хранения кода проекта
    • components------ Папка для общих компонентов
    • page------ Папка для хранения страниц
    • App.js------ корневой компонент
    • App.css------ корневой компонент стилей
    • index.js------ Файл входа в проект
    • index.css------ Общие стили для проекта
  • .gitgnore------ записыватьgitфайл конфигурации
  • package.json------ файл конфигурации проекта
  • README.md------ Информационный проект

Помните нашу компонентную картинку?

582_1.png

один из нихAPPЭто корневой компонент, через который мы пишем другие компоненты, такие какHeader,Asideа другие компоненты устанавливаются на корневой компонент.

4. команда нпм

npm start       // 使用 webpack-dev-server 启动服务查看应用
npm build       // 打包生成生产文件
npm test        // 进行软件测试(不常用)
npm eject       // 将所有的配置文件暴漏出来(不常用且不建议用)

Восемь, использование реактивного маршрутизатора

1. Что такое реактивный маршрутизатор

react-routerэто дляReactзаписыватьSPAПрименить действиеВнешняя маршрутизацияи родился.

(1) Внешняя маршрутизация (может быть немного простой)

Внешняя маршрутизациячерезHTML5новый APIHistoryДля работы принцип заключается в том, что меняется адрес URL-адреса, но это не вызывает перезагрузку, и в то же времяjavascriptИзменения можно отслеживать.
Есть два типа:

  • HashRouter: использоватьадресная строка URLиз#Назадхэш-значение

604_1.png

  • BrowserRouter: с помощью браузераHistory API, адресная строка не содержит#, выглядит красивее

606_2.png

Ни один из приведенных выше двух случаев не вызовет функцию перехода URL-адреса.

SPAполное имяSingle Page web Application, как следует из названия, толькоодностраничное приложение,пройти черезjavascriptВыполните рендеринг в реальном времени, чтобы обновить страницу.
То есть текущий маршрут используется для определения того, какие компоненты должны быть загружены на страницу, чтобы представить разные страницы и эффекты.

2. Использование реактивного маршрутизатора

(1) Установка и использование

Откройте окно командной строки в папке проекта дляnpmскачать

npm i react-router-dom -S

Примечание: мы скачалиreact-router-domвместоreact-routerРазница между ними:

  • react-router:при условииrouterосновной API. Такие какRouter,Route,Switchждать, ноAPI для маршрутизации переходов к операциям dom не предоставляется.;
  • react-router-dom:при условииBrowserRouter,Route,Linkи т. д. апи,Вы можете запускать события для управления маршрутизацией через операции dom..

react-router-domсодержитreact-router, поэтому выбираемreact-router-dom.

(2) Общие компоненты

а. Маршрутный прыжок

В многостраничных приложениях обычно используетсяaВкладка для перехода на страницу

<a href="http://localhost:3000">跳转页面</a>

Использование в одностраничных многофункциональных приложенияхreact-routerЗатем используйте компонент перехода маршрутизации

import {Link, NavLink} from "react-router";
<Link activeClassName="nav-active" className="nav" to="/about">About</Link>
<NavLink activeClassName="nav-active" className="nav" to="/home">Home</NavLink>
  • activeClassName: На текущем маршруте соответствующий компонент автоматически добавит этот класс.
  • className: текущее имя класса компонента
  • to: Маршрут, соответствующий текущему компоненту

Linkкомпоненты сNavLinkВсе компоненты могут выполнять переходы маршрутизации, разница в том, что текущая маршрутизация соответствуетNavLinkбудут добавлены автоматическиclass: active,а такжеLinkНе будет.

б. Зарегистрируйте маршрут
import {Route} from "react-router";
<Route path="/home" component={Home}></Route>
<Route exact path="/about" component={About}></Route>
  • path: Маршрут для прослушивания
  • component: Компонент, который будет привязан к этому маршруту
  • exact: необязательно, если не написано, тоfalse, выбрать ли строгое соответствие

Когда текущий маршрут соответствует маршруту, ограниченному компонентом маршрутизации, будет отображаться связанный компонент.

(a) Маршрутизация строгого сопоставления и нечеткого сопоставления

Существует не только один уровень маршрутизации, но иногда и несколько уровней вложенности, например следующий:

606_2.png
нечеткое соответствиеа такжеполное совпадение, все ссылаются на шаблон соответствия текущего компонента текущему маршруту:

  • нечеткое соответствие: Включите этот компонент, если текущий маршрут равен или содержит (обратите внимание на уровень) соответствующий маршрут.
    • http://localhost:3000/home/a/b/cвключить маршруты/home
    • http://localhost:3000/a/b/home/cне включает маршрутизацию/home(неправильный уровень)
  • полное совпадение: этот компонент активен только в том случае, если текущий маршрут равен соответствующему маршруту.
    • http://localhost:3000/homeи маршрутизация/homeравный
    • http://localhost:3000/home/aи маршрутизация/homeне равный
в. Перенаправить маршрут

Вы явно настроили маршрутизацию/home, но некоторые пользователи любят делать наоборот, и вводить его в адресную строку/nothing, а вы не прописали этот маршрут, что мне делать?
В это время вы можете отправиться на Tung Chung Road.перенаправить маршрутТеперь незарегистрированные маршруты будут перенаправлены на указанный вами маршрут.перенаправить маршрут.
часто можно использовать как некоторые404,страница отсутствуетМетод прыжка по маршруту в других ситуациях.

import {Redirect, Route} from "react-router";
<Route ....../>
<Route ....../>
<Redirect to="/home"/>
  • to: На какой маршрут мне нужно перенаправить?

Redirectразместить во всехRouteниже, когда вышеRouteЕсли совпадения нет, маршрут будет перенаправлен на указанный маршрут.

г. Маршрутизация коммутатора

Подумайте об этом, если ваша маршрутизация появится/homeа также/home/abcа также/home/a/b/cи т.д. Такой маршрут, когда маршрут/homeКогда все три маршрута оказываются одновременно, но вы хотите только рендер одного из них, мы можем использоватьSwitchкомпоненты.
использоватьSwitchВсе компоненты обертываютсяRouteа такжеRedirect, при наличии нескольких совпадающих маршрутов будет отображаться только первый совпадающий компонент.

import {Switch, Route, Redirect} from "react-router";
<Switch>
    <Route ..../>
    <Route ..../>
    <Redirect to="..."/>
</Switch>
е. Маршрутизатор

Вы хотите использовать компонент перехода по маршруту и ​​компонент маршрута, и есть компонент маршрутизатора, и компонент маршрутизатора должен обернуть эти два компонента.

import {HashRouter, BrowserRouter} from "react-router";

Как правило, для того, чтобы сделать всеРеагировать приложениеМожно использовать компоненты маршрутизации, поэтому обычно мы оборачиваем маршрутизатор корневым компонентом.

ReactDOM.render( 
    <BrowserRouter>
        <App/>
    </BrowserRouter>,
    document.querySelector("#root")
);

Есть два компонента маршрутизатора, а именноHashRouterа такжеBrowserRouter, соответствующие двум методам маршрутизации соответственно.

(3) Компонент маршрутизации

Компоненты маршрутизации и общие компоненты

  1. пишется по-другому
    • Общие компоненты:<Demo></Demo>
    • Компонент маршрутизации:<Route path="/demo" component={Demo}/>
  2. разные места хранения
    • Общие компоненты:папка компонентов
    • Компонент маршрутизации:папка страницы
  3. полученоpropsразные
    • Общий компонент: передать вышеперечисленное в соответствии с тегом компонента, что получено
    • Метка маршрутизации: получит три фиксированных атрибута
{
  "history": {
    "length": 18,
    "action": "PUSH",
    "location": {
      "pathname": "/home",
      "search": "",
      "hash": "",
      "key": "tvfyve"
    }
  },
  "location": {
    "pathname": "/home",
    "search": "",
    "hash": "",
    "key": "tvfyve"
  },
  "match": {
    "path": "/home",
    "url": "/home",
    "isExact": true,
    "params": {}
  }
} 

3. Вложенная маршрутизация

Предположим, у нас есть компонент маршрутизации какHome, используемый в корневом компонентеLinkПерешел на этот маршрут, текущий маршрут/home, доступный в компонентеHomeесть еще дваLink, что приводит к маршрутизации соответственно/home/messageа также/home/newsЗатем в компоненте есть другие компоненты маршрутизации. Здесь в игру вступает вложенная маршрутизация.
Например, следующий код:

class Home extends Component{
    render(){
        return (
            <div>
                <Link to="/home/message">Message</Link>
                <Link to="/home/news">News</Link>
                <hr/>
                <Route path="/home/message" component={Message} />
                <Route path ="/home/news" component={News} />
            </div>
        )
    }
}

4. Программная маршрутизация

Если мы скажем, что хотим, чтобы пользователь нажимал кнопку для входа, если он учитель, то он перейдет на страницу учителя, а если он ученик, то он перейдет на страницу ученика, это, очевидно, зависит отLinkне может быть сделано, мы можем пройтиjsСделайте переходы маршрутизации (такжеreact-routerна основеHistory APIнаписано)

class Message extends Component {
    state = {
        messageArr:[
            {id:"01", title: "消息1"},
            {id:"02", title: "消息2"},
            {id:"03", title: "消息3"},
        ]
    }
    // 编程式路由导航
    pushShow = (id, title)=>{
        // push跳转 + 携带 params参数
        this.props.history.push(`/home/message/detail/${id}/${title}`);
        
        // push跳转 + 携带 search参数
        // this.props.history.push(`/home/message/detail?id=${id}&title=${title}`);
        
        // push跳转 + 携带 state参数
        // this.props.history.push(`/home/message/detail`, {id,title});
    }
    replaceShow = (id, title)=>{
        // replace跳转 + 携带 params参数
        this.props.history.replace(`/home/message/detail/${id}/${title}`);
        
        // replace跳转 + 携带 search参数
        // this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`);
        
        // replace跳转 + 携带 state参数
        // this.props.history.replace(`/home/message/detail`, {id, title});
    }
    // 后退
    goBack = ()=>{
        this.props.history.goBack();
    }
    // 前进
    goForward = ()=>{
        this.props.history.goForward();
    }
    // 跳转指定位置
    go = ()=>{
        // 向前两步
        this.props.history.go(2);
        
        // 后退两步
        this.props.history.go(-2);
    }
    render() {
        const {messageArr} = this.state;
        return (
            <div>
                <ul>
                    {
                        messageArr.map(item=>{
                            return (
                            <li key={item.id}>
                                <Link to={`/home/message/detail/${item.id}/${item.title}`}>{item.title}</Link>
                                &nbsp;<button onClick={() => this.pushShow(item.id, item.title)}>push查看</button>
                                &nbsp;<button onClick={() => this.replaceShow(item.id, item.title)}>replace查看</button>
                            </li>
                            )
                        })
                    }
                </ul>
                <hr/>
                <Route path="/home/message/detail/:id/:title" component={Detail} />
                <button onClick={this.goBack}>goBack</button>
                &nbsp;
                <button onClick={this.goForward}>goForward</button>
                &nbsp;
                <button onClick={this.go}>go</button>
            </div>
        )
    }
}

Подводя итог приведенному выше коду:

  1. Программная маршрутизация осуществляется черезpropsсерединаhistoryОбъект для работы (все методы объекта, вызывающий метод:this.props.history.xxx)
  2. Общий метод:
    • push(route[, state]): Перейти к указанному маршруту (с историей)

    • replace(route[, state]): Перейти к указанному маршруту (без истории)

    • goBack(): вернуться на один

    • goForward(): вперед один

    • go(num): перейти к указанному количеству шагов, когдаnumКогда это положительное число, оно идет вперед, когдаnumЕсли он отрицательный, он отступит.

5. Компонент withRouter

Иногда мы хотим использовать функцию компонента маршрутизации в других компонентах, таких как панель навигации, которая должна принадлежать общедоступному компоненту, но функция навигационной ссылки внутри является функцией компонента маршрутизации. Это?
существуетreact-router, предоставляет такой метод, который позволяет общим компонентам иметь функцию маршрутизации компонентов, то естьwithRouter()метод.
Посмотрите демо:

import {withRouter} from "react-router-dom";

class Header extends Component {
    // withRouter后该组件也有了路由组件的功能
    goBack = ()=>{
        this.props.history.goBack();
    }
    go = ()=>{
        this.props.history.go(2);
    }
    goForward = ()=>{
        this.props.history.goForward();
    }
    render() {
        return (
            <div>
                <h1>This is a React-router-dom Test!</h1>
                <button onClick={this.goBack}>goBack</button>
                &nbsp;
                <button onClick={this.goForward}>goForward</button>
                &nbsp;
                <button onClick={this.go}>go</button>
            </div>
        )
    }
}

// withRouter 用于给一般组件添加上路由组件特有的功能,返回一个新组件
export default withRouter(Header);

9. Передача параметров между компонентами маршрутизации

Передача контента между родительским и дочерним компонентами может осуществляться черезpropsпередавать параметры, но компонент маршрутизации не имеет своей метки, так как передать параметры?
Помните о конкретном компоненте маршрутизацииpropsмы можем использоватьHistory APIСуществует три способа передачи параметров между компонентами маршрутизации.

  • params
  • search
  • state

1. Передайте параметр params

// 父组件
class Parent extends Component {
    state = {
        messageArr:[
            {id:"01", title: "消息1"},
            {id:"02", title: "消息2"},
            {id:"03", title: "消息3"},
        ]
    }
    render() {
        const {messageArr} = this.state;
        return (
            <div>
                <ul>{
                 messageArr.map(item=>{
                    // 向路由组件传递 params参数
                    return <li key={item.id}><Link to={`/home/message/detail/${item.id}/${item.title}`}>{item.title}</Link></li>
                    })
                }</ul>
                <hr/>
                {/* 声明接受 params参数,可以在 props中的 match属性的 params属性里获得 */}
                <Route path="/home/message/detail/:id/:title" component={Child} />
            </div>
        )
    }
}
// 子组件
class Child extends Component {
    state = {
        contentArr:[
            {id:"01", content: "你好中国"},
            {id:"02", content: "你好世界"},
            {id:"03", content: "你好帅哥"},
        ]
    }
    render() {
        console.log(this.props);
        // 获取 params参数
        const {id, title} = this.props.match.params
        const findResult = this.state.contentArr.find(obj=>obj.id == id).content;
        return (
            <div>
                <ul>
                    <li>ID: {id}</li>
                    <li>TITLE: {title}</li>
                    <li>CONTENT: {findResult}</li>
                </ul>
            </div>
        )
    }
}

В использованииparamsПри передаче параметров вы будете четко видеть, что параметры отображаются в виде маршрутов, например:

  • http://localhost:3000/home/message/用户1/文章32

выше классаПользователь 1а такжеСтатья 32, который является переданным параметром.
кparamsПараметры, переданные методом, должны быть объявлены и приняты в маршрутизации, прежде чем их можно будет использовать.

<Route path="/home/message/detail/:id/:title" component={Child} />

Назад:idа также:titleпеременный маршрут, который можно пройти черезpropsизmatchПримите, чтобы получить контент здесь.

const {id, title} = this.props.match.params

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

это зависитgetметод запроса.

  • http://localhost/home/message?id=1&title=abc

которыйjavascriptможет быть полученurlсередина?Следующее тело запроса. Так что мы можемmapТеги, возвращенные в модификации, следующие

<li key={item.id}><Link to={`/home/message/detail?id=${item.id}&title=${item.title}`}>{item.title}</Link></li>

И этому способу не нужно объявлять получение в маршруте.
пройти черезpropsсерединаlocationполучать

const search = this.props.location.search;
// 获取到的格式时: ?id=xxx&title=xxx 所以还需要加工一下
const {id, title} = qs.parse(search.slice(1));

3. Передайте параметр состояния

пройти черезHistoryAPIдля передачи данных:

<li key={item.id}><Link to={{pathname: `/home/message/detail`, state:{id:item.id, title:item.title}}}>{item.title}</Link></li>

不需要在路由链接中添加任何东西,也不需要路由进行声明接收。 более красивый.
существуетpropsсерединаlocationполучатьstateАтрибуты

const {id, title} = this.props.location.state;

4. Сравнение трех

Маршрутизируемые компоненты менее полезны, потому что все они от чего-то зависят:

  • params: Зависит от линка маршрутизации, линк не красивый
  • search: Зависит от линка маршрутизации, линк не красивый
  • state: Опираясь на историю(HistoryAPI), ссылка красивая, но при прямом вводе по ссылке выдает ошибку (нет истории)

Поэтому попробуйте использовать другие способы передачи параметров.Если вам придется использовать его, ограниченное сравнение:

  1. params(чаще всего используется)
  2. search(чаще используется)
  3. state(редко используемый)

Десять, использование редукса

614_1.png

Предположим, наши компоненты похожи на эту картинку, с компонентами, вложенными друг в друга.
В это время делается запрос вКомпонент Еданные в , датьКомпонент Аа такжеКомпонент FПользуйтесь, как с этим бороться?

  • Способ 1: через константуpropsПередача параметров, но это очень долго и трудозатратно
  • Способ 2: ИспользованиеPubsub.jsи так далее для функции публикации/подписки сообщений
  • Способ 3: Использованиеreact-reduxЦентрализованное управление данными

которыйreduxЕго можно рассматривать как экономку, отвечающую за помощь в хранении общедоступных данных.

1. Установите редукс

npm i redux -S

2. Основные концепции

616_1.png

reduxЕсть три основных понятия

  1. action:
    • Объект действия (содержимое действия)
    • Содержит два свойства: а.type: Представляет атрибут, значениенить, уникальный, необходимый атрибут (что делать) б.data: атрибут данных, значениелюбой тип, необязательные атрибуты (как это сделать)
    • Например:{ type: "ADD_STUDENT", data: { name: "tom", age: 18 } }
  2. reducer:
    • Используется для инициализации состояния и состояния обработки (инициализация данных и управление данными)
    • При механической обработке, согласно старомуstateа такжеaction, генерируя новыйstateчистая функция
    • Есть два параметра, один - предыдущее состояние (prevstate) и объект действия (action)
  3. store:
    • Будуstate,action,reducerсвязанные объекты (мозг)

Мы можем примерноreduxпредставьте себе семьюГостиная, и мыклиент( component), мы называемофициант( action) для заказа и других операций, а официант передаетуправляющий делами( store), менеджер заказалзадняя кухня( reducer) приготовить, а затем менеджер передает его заказчику после того, как блюдо будет готово

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

(1) Создать папку

существуетsrcпапка созданаreduxпапка для храненияreduxсвязанный контент

  • Compnoent------ Хранить папки, связанные с компонентами
  • redux------ место храненияreduxсвязанные папки с содержимым
    • actions------ место храненияactionсвязанные папки с содержимым
    • reducers------ место храненияreducerсвязанные папки с содержимым
    • constant.js------ Сохраняет файлы с каноническими именами
    • store.js------ записыватьstoreдокумент

Позвольте мне объяснить вам один за другим. Напишите самое простоеredux

/**
 * store.js
 * 该文件专门用于暴漏一个 store对象,整个应用只有一个 store对象
 */
// 引入 createStore,专门用于创建 redux中最为核心的 store
import {createStore} from "redux";
// 引入为 Count组件服务的 reducer
import countReducer from "./count_reducer";
const store = createStore(countReducer)
// 暴露 store对象
export default store;
/**
 * / reducer / count.js
 * 1. 该文件是用于创建一个为 Count组件服务的 reducer,reducer的本质就是一个函数
 * 
 * 2. reducer函数会收到两个参数,分别为:之前的状态(preState),动作对象(action)
 * 
 * 3. 会自动调用一次 reducer(初始化)
 */
// 初始化的状态
const initState = 0;
export default function countReducer(preState = initState, action){
    if(preState === undefined) preState = 0; 
    // 从 action对象中获取 type,data
    const {type, data} = action;
    // 根据 type觉得如何加工数据
    switch (type) {
        case 'increment': // data
            return preState + data;
        case 'decrement': // 如果是减
            return preState - data;
        default:
            return preState;
    }
}
// / Component / Count.js 
import React, { Component } from 'react'
// 引入store
import store from "../../redux/store";
export default class Count extends Component {
    // 加法
    increment = ()=>{
        const {value} = this.selectNumber;
        // 发送动作对象给 store
        store.dispatch({
            type: "increment",
            data: value*1
        })
    }
    render() {
        return (
            <div>
                <h1>当前求和为:{store.getState()}</h1>
                <select ref={c=>this.selectNumber = c}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>
                <button onClick={this.increment}>+</button>
            </div>
        )
    }
}

Выше самое краткоеredux, давайте проанализируем процесс:

  1. записыватьCountкомпоненты, создатьCountкомпонент, соответствующийReducerдокумент
  2. записыватьReducerкод и броски::
    • Reducerэто чистая функция
    • обычно используетсяSwitchпровестиactionсерединаtypeсуждение
    • Возвращаемое значение функции является измененным значением
  3. Создайтеstoreи напишите код:
    • инструкцииcreateStore()метод созданияstore, Это параметрreducer
    • написатьCountкомпонентreducerимпорт
  4. импортировать в компонентstoreи сделать вызов:
    • в методе с использованиемdspatch()методstoreпередачаaction
    • dispatchАргумент является объектом (т.е.actionобъект действия)

(2) Используйте поток

Выше приведен общий процесс создания, и общий используемый процесс выглядит следующим образом:

  1. storeАвтоматически вызывается один раз при инициализацииreducerИнициализированное значение
  2. КомпонентactionДатьstore,storeПосле вынесения решения направьте его соответствующимreducer
  3. reducerсогласно сactionвнутреннийtypeВернуть новое значение после соответствующей обработки данных
  4. storeПолучить новое значение возвращается и замените старое значение
  5. По методуstore.getState()получить текущийstoreстоимость тела

(3) Используйте асинхронный редукс

Если нам нужно использовать асинхронныйreduxЕсли это так, вам нужно использовать другой плагин:redux-thunk

npm i redux-thunk -S

Этопромежуточное ПО, чтобы помочь справиться с асинхроннымredux,
Асинхронныйactionзначение функции Сделайте нормальный в функцииdispatch()действовать

export const createIncrementAsyncAction = (data, time=500)=>{
    // 返回一个 action
    return ()=>{
        setTimeout(()=>{
            store.dispatch(createIncrementAction(data));
        }, time);
    }
}

В то же время мы будемstoreПоместите настройкиПоддержка выполнения промежуточного программного обеспечения,пройти черезreduxизapplyMiddleware()метод может загрузить промежуточное ПО, его параметром является промежуточное ПО, а затемapplyMiddleware()будет использоваться какcreateStore()Вводится второй параметр.

// store.js
// 引入 applyMiddleware,专门用于执行中间件
import {createStore, applyMiddleware} from "redux";
// 引入为 Count组件服务的 reducer
import countReducer from "./count_reducer";
// 引入 redux-thunk,用于支持异步 action
import thunk from "redux-thunk";
// 暴露 store对象
export default createStore(countReducer, applyMiddleware(thunk));

(4) Мониторинг изменений состояния

Вы написали, что узнали, хотяreduxСтатус внутри действительно обновился, а страница не изменилась?
Помните, какая функция используется для рендеринга страницы?render()функция. но вreduxКогда состояние меняется, нам не помогает вызовrender()функция, поэтому нам нужно вручную реализовать отрисовку страницы в реальном времени.
Здесь мы используемreduxизstoreВверхsubscribe()способ прослушиванияreduxПри изменении состояния параметр представляет собой функцию, с которой нам удобно работать.
Обычно мы пишем его в корневом теге (упрощенно, не нужно использовать каждыйreduxкомпоненты написаны заново)

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import store from "./redux/store"
ReactDOM.render(
    <App />,
  document.getElementById('root')
);
// 精简写法
store.subscribe(()=>{
  ReactDOM.render(
      <App />,
    document.getElementById('root')
  );
})

4. Меры предосторожности

  1. Обычно используется дляreduxЕсли вам нужно использовать более одного компонента, создайтеactionsа такжеreducersхранить несколькоactionа такжеreducer
  2. То же,storeОпределенно более одного загруженногоreducer, поэтому мы используемreduxизcombineReducers()способ объединить всеreducer
    • combineReducers()Параметром метода является объект, в котором хранятся всеreducer
import {createStore, applyMiddleware, combineReducers} from "redux";
import countReducer from "./reducers/count";
import personReducer from "./reducers/person";
import thunk from "redux-thunk";
// 汇总所有的 reducer
const allReducer = combineReducers({
    count: countReducer,
    persons: personReducer,
});
export default createStore(allReducer, applyMiddleware(thunk));


  1. потому чтоreduxЕсть еще много проблем с дизайном, таких как:
    • Один компонент должен делать: сstoreСделка, приобретение данных, мониторинг данных изменений, распространениеactionОбъекты и т.д. Компонент отвечает за слишком много вещей.
    • Требуется дополнительный мониторингreduxСостояние изменяется, чтобы обновить состояние и отобразить страницу.
    • Итак, кто-тоreduxОптимизирована и введена другая библиотекаreact-redux(Не волнуйтесь, это ничем не отличается, просто немного больше оптимизации, я расскажу об этом позже)
  2. Нельзя использоватьredux, не используйтеredux(не важно какreduxещеreact-redux)
  3. нельзя использоватьredux, не используйтеredux(не важно какreduxещеreact-redux)
  4. нельзя использоватьredux, не используйтеredux(не важно какreduxещеreact-redux)

11. Понимать и использоватьreact-redux

Сказал раньше,react-reduxНа самом деле этоreduxОбновленная версияreduxзнание оптимизации.

620_1.png

1. Используйте компоненты-контейнеры и компоненты пользовательского интерфейса

Цель состоит в том, чтобы разделить слишком много работы над компонентом наКомпоненты пользовательского интерфейса (внутренние компоненты)а такжекомпонент-контейнер (внешний компонент), используется между двумя компонентамиpropsобщаться, чтобыstoreЗадача запроса состояния и изменения состояния там передается компоненту-контейнеру, а работа по написанию страниц через состояние, обновлению и рендерингу и т. д. передается компоненту пользовательского интерфейса.

Как только вы это поймете, вы сможете начать использоватьreact-reduxохватывать

2. Установка реактивного редукса

npm i react-redux -S

Не так много, чтобы сказать об этом.

3. Создайте папку

Для компонентов контейнера мы все используемcontainersпапка для хранения.

  • containers------ Папка для хранения компонентов контейнера
  • redux------ для храненияreact-reduxсвязанные папки

4. Создайте компонент-контейнер

компонент контейнера черезreact-reduxизconnect()метод создания.

// 引入 Count的 UI组件
import Count from "../../components/Count";
// 引入 connect用于连接 UI组件与 redux
import { connect } from 'react-redux'

// 该函数的返回值作为状态传递给 UI组件
function mapStateToProps(state){
    return {
        count: state,
    }
}
// 该函数的返回值作为操作状态的方法传递给 UI组件
function mapDispatchToProps(dispatch){
    return {
        add: data=>{
            console.log(1234);
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(Count);

использоватьconnect( )( )создать и выставитьCountКомпонент-контейнер для компонентов.
передачаconnectКогда имеет два параметра и должна быть функцией.

  • mapStateToProps( state ): возвращаемое значение этой функции будет использоваться какусловиепередается компонентам пользовательского интерфейса
    • state: параметрstateдляreact-reduxХорошо по умолчаниюstore.getState()
  • mapDispatchToProps( dispatch ): возвращаемое значение этой функции будет использоваться какМетоды управления состояниямиПередайте его компоненту пользовательского интерфейса, там синтаксический сахар, просто передайте объект (см. код ниже).
    • dispatch: параметрdispatchдляreact-reduxзадано по умолчаниюstore.dispatchметод

Это просто для удобства объяснения, и при его использовании можно использовать синтаксический сахар.

Несколько мест на заметку:

  1. вообще говоряКомпоненты пользовательского интерфейсаа такжекомпонент контейнераЗаписывается в файл, а какая папка существует, зависит от потребностей компании (обычноcontainers)
  2. в компоненте контейнераstoreиспользуется не для введения, а какpropsМетка передается компоненту-контейнеру.<Count store={store} />
  3. Синтаксический сахар:
// 引入 Count的 UI组件
import Count from "../../components/Count";
// 引入 connect用于连接 UI组件与 redux
import { connect } from 'react-redux'

// 精简写法
export default connect(
    state => ({count: state}),
    {
        add: data=> console.log(1234, data)
    }
)(Count);

5. Компонент провайдера

Если у вас много компонентов контейнера, передайте каждый компонент контейнераstore, вам не кажется, что это слишком сложно? такreact-reduxпри условииProviderКомпоненты используются для обработки этого, просто используйте корневой тег и поместитеstoreПередайте его, он может автоматически определить, какие компоненты нужно использоватьstoreи автоматически переходит к нему.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import store from "./redux/store"
// 优化3: 使用自带的 Provider自动判断哪些组件需要使用 store,从而自动导入
import { Provider } from "react-redux";
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

6. Отслеживайте изменения состояния

Вы обнаружили, что приведенный выше код больше не был написан?store.subscribe()Изменения состояния прослушивания, потому что создаем компоненты контейнераconnectУже помогите нам мониторить.

7. Связь между компонентами контейнера

Это на самом деле довольно просто, помнитеconnectпервый параметр первой функции? То, что передается компоненту пользовательского интерфейса,props, параметры которогоstate,этоstateдаstore.getState().
Но теперь твойstore.getState()уже не просто ценность, а всеreducerобъект, поэтому мы можем получить в нем значения других компонентов контейнера.

export default connect(
    state => ({count: state.count, personLength: state.persons.length}),
    {
        increment: createIncrementAction,
        decrement: createDecrementAction,
        asyncIncrement: createIncrementAsyncAction,
    }
)(Count);

8. Спецификации документа

Создано так много вещей, некоторые из них можно интегрировать, давайте приведем в порядок:

  • containers------ сборка контейнера для хранения папок с файлами (сборка пользовательского интерфейса и сборка контейнера вместе пишутся)
    • Count.js ------ Countкомпонент контейнера
    • Person.js ------ Personкомпонент контейнера
  • redux------ для храненияreact-reduxсвязанные папки
    • actions------ для хранения всехactionпапка

      • count.js------ для храненияCountкомпонентaction
      • person.js------ для храненияPersonкомпонентaction
    • reducers------ для хранения всехreducerпапка

      • count.js------ для храненияCountкомпонентreducer
      • person.js------ для храненияPersonкомпонентreducer
      • index.js------ Используется для хранения сводкиreducerдокумент(combineReducers()метод)
    • constant.js------ Используется для хранения некоторых файлов с общими именами

    • store.js ------ react-reduxизstoreдокумент

9. Опять же, не используйте эту штуку, если можете! !

12. React16.8 и некоторые расширения

1. Ленивый () и приостановка

Предыдущие компоненты загружаются вместе, что увеличивает нагрузку на сервер, поэтомуreactвыпускатьlazy()Ленивая загрузка, загрузка компонентов по требованию.
вышел с этимSuspense, он решает белый экран, когда компонент не загружается в процессе загрузки, используется для отображения другого контента.

import React, { Component, lazy, Suspense } from 'react'
import {Route, Link} from "react-router-dom"

// import Home from "./Home";
// import About from "./About";
import Loading from "./Loading";
// lazy() 方法的参数是一个函数,返回需要加载的组件
const Home = lazy(()=>import("./Home"))
const About = lazy(()=>import("./About"))
export default class index extends Component {
    render() {
        return (
            <div>
                <Link to="/home">Home</Link>
                <Link to="/about">About</Link>
                <hr/>
                {/* Suspense 用于解决加载组件时的白屏,可以显示其他的内容,而其他内容不允许使用 lazy加载 */}
                <Suspense fallback={<Loading/>}>
                    <Route path="/home" component={Home}></Route>
                    <Route path="/about" component={About}></Route>
                </Suspense>
            </div>
        )
    }
}
  • lazyАргумент представляет собой функцию, использующуюimportимпортировать компонент и вернуть
  • SuspenseсвойстваfallbackЗначение атрибута атрибутаметка компонентавместо компонентов
  • SuspenseИспользуемый компонент нельзя использоватьlazyСделайте ленивую загрузку.

2. Hook

React16.8Можно сказать, что он дает функциональным компонентам пружину, потому что у него естьHook, можно добиться некоторыхstate, функция жизненного цикла,refsи другие характеристики.
Давайте пройдемся по ним один за другим:

(1) stateHook

Функциональные компоненты могут быть реализованы с использованиемstateФункции:


export default function Demo() {
    // useState返回一个数组,只有两个元素(只有两个元素)
    // 元素1 为状态,元素2 为更新状态的方法
    // 第一次调用时以及将count进行底层存储,所以 Demo重复渲染不会重置count数据
    const [count, setCount] = React.useState(0); // 初始值赋为 0
    const [name, setName] = React.useState("Tom");
    function add(){
        // 进行状态赋值
        // setCount(count + 1); // 写法1,直接将原来的状态值覆盖
        setCount(count=> count+1); // 写法2,参数为函数,接受原本的状态值,返回新的状态值,覆盖原来的状态
    }
    return (
        <div>
            <h3>名字:{name}</h3>
            <h2>当前求和:{count}</h2>
            <button onClick={add}>点击加一</button>    
        </div>
    )
}

(2) EffectHook

Вы можете заставить функциональные компоненты достигать чего-то вродекрючки жизненного циклаФункции:

export default function Demo() {
    const [count, setCount] = React.useState(0);
    const [name, setName] = React.useState("Tom");
    function add(){
        setCount(count=> count+1);
    }
    function updName(){
        setName(name=>"Jerry");
    }
    function unmount(){
        ReactDOM.unmountComponentAtNode(document.querySelector("#root"));
    }
    // useEffect接收两个参数,第一个为函数体,第二个为检测的对象(数组),当检测的对象状态发生改变,就会触发函数
    // 不填写第二参数时,检测所有元素,相当于 componentDidUpdate生命周期函数
    React.useEffect(()=>{
        // console.log("asdf")
        let timer = setInterval(()=>{
            setCount(count=>count+1);
        },1000);
        return ()=>{        // 在 useEffect中的函数体里返回的函数,相当于 componentWillUnmount生命周期函数
            console.log("unmount")
            clearInterval(timer);
;        }
    },[]) // 数组为空是谁也不检测,只执行一次函数,相当于生命周期函数的 componentDidMount
    return (
        <div>
            <h2>当前求和:{count}</h2>
            <button onClick={add}>点击加一</button>
            <h2>当前名字:{name}</h2>
            <button onClick={updName}>修改名字为Jerry</button>
            <button onClick={unmount}>卸载组件</button>
        </div>
    )
}

можно поставитьuseEffect HookДумайте об этом как о комбинации трех функций:

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

(3) refHook

refHookВы можете заставить функциональные компоненты достигать чего-то вродеrefхарактеристики

export default function Demo() {
    const [count, setCount] = React.useState(0);
    function add(){
        setCount(count=> count+1);
    }
    function show(){
        // 获取文本框内容
        alert(myInput.current.value);
    }
    // 生成一个容器
    const myInput = React.useRef();
    return (
        <div>
            <h2>当前求和:{count}</h2>
            {/* 绑定容器 */}
            <input type="text" ref={myInput}/>
            <button onClick={add}>点击加一</button>
            <button onClick={show}>点击展示数据</button>
        </div>
    )
}

Это несложно.

3. Fragment

существуетreactПри рендеринге компонентов, когда у вас появляется все больше и больше компонентов, вы заметили, что ваши уровни DOM становятся все больше и больше, что немного неприглядно, поэтому кажетсяFragment.
можно использоватьFragmentТег заменяет корневой тег компонента вReactОн будет обработан при разборе, Это делает уровень сгенерированного кода более лаконичным.

export default class Demo extends Component {
    render() {
        return (
            // 使用空标签可以达到一样的效果,但是空标签不允许包含任何的属性
            <Fragment key={1}>
                <input type="text"/>
                <input type="text"/>
            </Fragment>
        )
    }
}

4. Context

ContextЯвляется новой системой связи компонентов, компоненты, обычно используемые в коммуникационных предшественниках [] и [] между потомством сборки.

// 1. 创建一个 Context容器对象
const UserNameContext = React.createContext();
// 1.1 拿到 Provider与 Consumer属性
const {Provider, Consumer} = UserNameContext;
export default class A extends Component {
    state={username: "Tom"}
    render() {
        return (
            <div className="a">
                <h1>我是A组件</h1>
                <p>我的用户名是:{this.state.username}</p>
                {/* 2 使用组件,后代组件都能收到来自 value的值,就在 this上的 context属性上(需提前声明)  */}
                <Provider value={this.state.username}>
                    <B/>
                </Provider>
            </div>
        )
    }
}
class B extends Component {
    // 3. 声明接受 Context
    static contextType = UserNameContext;   // 此方法只适用于 类组件
    render() {
        console.log(this.context);  // Tom
        return (
            <div className="b">
                <h2>我是B组件</h2>
                <p>A的用户名是:{this.context}</p>
                <C/>
            </div>
        )
    }
}
function C() {
    return (
        <div>
             <div className="c">
                <h3>我是C组件</h3>         
                {/* 3.2 使用 Consumer组件进行声明接受(类组件和函数式组件都可以)  */}
                <Consumer>
                    {value=> ("A的用户名是:" + value)}
                </Consumer>
             </div>
        </div>
    )
}

5. PureComponent

В компоненте, пока реализацияsetState(), даже если данные состояния не обновляются, компонент перезапуститсяrender().
Пока компоненты сбрасываютсяrender(), он автоматически сбрасываетсяrender()Дочерний компонент, даже если дочерний компонент не использует никаких данных из родительского компонента.
Оба этих случая приводят к повторному рендерингу, что делает его неэффективным.

Эффективная практика: только компонентыstateилиpropsБлюдо переделывается, когда есть изменениеrender().

  • Решение 1. Через функцию жизненного циклаshouldComponentUpdate()Оценивайте данные и выполняйте повторный рендеринг
  • Решение 2. Компоненты класса передают наследованиеPureComponentКомпонент, автоматическая оценка данных (поверхностное сравнение --- оценка значения адреса) (обычно используется)
import React, { Component, PureComponent } from 'react'
export default class Parent extends PureComponent {
    state = {carName: "奔驰"}
    changeCar = ()=>{
        this.setState(state=>({carName:"迈巴赫"}));
    }
    // shouldComponentUpdate有两个参数,分别是准备修改的 props和 state
    // shouldComponentUp date(nextProps, nextState){
    //     console.log(nextProps, nextState);  // 目标要修改的props和state
    //     console.log(this.props, this.state);   // 还未修改原本的props和state
    //     return !this.state.carName === nextState.carName;
    // }
    render() {
        console.log("parent render");
        return (
            <div className="parent">
                <h1>Parent</h1>
                <p>我的车是:{this.state.carName}</p>
                <button onClick={this.changeCar}>点击换车</button>
                <Child/>
            </div>
        )
    }
}
class Child extends PureComponent {
    
    // shouldComponentUpdate(nextProps){
    //     return !this.props.carName === nextProps.carName
    // }
    render() {
        console.log("child render");
        return (
            <div className="child">
                <h2>Child</h2>
                {/* <p>父亲的车是:{this.props.carName}</p> */}
            </div>
        )
    }
}

6. Родительские и дочерние компоненты

Нечего сказать, сразу к коду:

import React, { Component, PureComponent } from 'react'
import "./index.css"

export default class Parent extends PureComponent {
    state = {carName: "奔驰"}
    changeCar = ()=>{
        this.setState(state=>({carName:"迈巴赫"}));
    }
    render() {
        console.log("parent render");
        return (
            <div className="parent">
                <h1>Parent</h1>
                <p>我的车是:{this.state.carName}</p>
                {/* A组件 与 B组件 形成父子组件的第二种方法 */}
                {/* <A>
                    <B/>
                </A> */}
                {/* 类似于 Vue的插槽 */}
                <A render={(name)=><B name={name}/>}/>  
            </div>
        )
    }
}

class A extends PureComponent {
    render() {
        console.log("A render");
        return (
            <div className="a">
                <h2>A</h2>
                {/* A组件 与 B组件 形成父子组件的第一种方式 */}
                {/* <B/> */}
                {/* {this.props.children} */}
                {this.props.render("Tom")}
            </div>
        )
    }
}
class B extends PureComponent {
    render() {
        console.log("B render");
        return (
            <div className="b">
                <h2>B</h2>
                <p>{this.props.name}</p>
            </div>
        )
    }
}

7. ErrorBoundary

Когда ваш компонент имеет связь между родительским и дочерним компонентами, если в вашем дочернем компоненте есть ошибка, это приведет к тому, что родительский компонент рухнет вместе.Есть ли способ контролировать ошибку в одном компоненте и предотвратить ее распространение?
Ответ - да, есть две функции:

  • getDerivedStateFromError(error)
  • componentDidCatch(error, info)

Над кодом:

import React, { Component, Fragment } from 'react'
import Child from "./Child";
// 错误边界即把组件的错误信息控制在一个组件中,不使他扩散而导致程序崩溃
export default class Person extends Component {
    state = {
        hasError: "",   // 用于标识子组件是否产生错误
    }
    // 当子组件发生错误时会触发该生命周期函数,且参数为错误信息
    // 只适用于生产环境,只能捕获后代组件生命周期产生的错误
    static getDerivedStateFromError(error){
        // 一般用于处理错误出现时返回给用户展示的东西
        console.log("出错了");
        console.log(error);
    }
    // 组件渲染过程中出错就会触发该生命周期函数
    componentDidCatch(error, info){
        // 一般用于统计错误,反馈给雾浮起,用于通知程序员进行bug修改
        console.log("渲染组件出错");
        console.log(error, info)
    }
    render() {
        return (
            <Fragment>
                <h2>我是Parent组件</h2>
                {
                    this.state.hasError ? 
                        <h2>当前网络不大行,建议买高级网络套餐好吧</h2> :
                        <Child/>                
                }
            </Fragment>
        )
    }
}

8. Краткое описание методов связи компонентов

  • Отношения между компонентами:
    1. компонент родитель-потомок
    2. родственный компонент
    3. внучатые компоненты (межуровневые компоненты)
  • Несколько способов связи:
    1. props
      1. children props
      2. render props
    2. Подписка на новостиpubsub, event
    3. Централизованное управлениеredux, dva, react-redux
    4. контекст Модель производителя-потребителей
  • Лучшее совпадение:
    • Родительский и дочерний компоненты:props
    • Компоненты Brother: подписка и публикация сообщений, централизованное управление
    • Внучатые компоненты: публикация подписки на сообщения, централизованное управление,conText

Тринадцать, последний

Это некоторые из моих учебных заметок для изучения React.Если в будущем будет другой контент, я должен углубиться в него и написать отдельную статью.

Новичок в пути, пожалуйста, включите много.
Я MoonLight, начинающий маленький фронтенд.