34 навыка, которыми должен обладать React-разработчик [почти 1 Вт слов]

внешний интерфейс React.js
34 навыка, которыми должен обладать React-разработчик [почти 1 Вт слов]

предисловие

React — это один из трех интерфейсных фреймворков, а также навык в разработке;
В этой статье приведены некоторые навыки и методы разработки React из фактической разработки, которая подходит для студентов, которые только начинают работать с React или имеют определенный опыт работы с проектами.
Серийные статьи:36 навыков, которые должны знать разработчики Vue [почти 1W слов]

Адрес источника

пожалуйста ткните, добро пожаловать звезда

визуализация

react 技巧.png

1 компонент связи

1.1 props

Подсборка

import React from "react";
import PropTypes from "prop-types";
import { Button } from "antd";

export default class EightteenChildOne extends React.Component {
  static propTypes = { //propTypes校验传入类型,详情在技巧11
    name: PropTypes.string
  };

  click = () => {
    // 通过触发方法子传父
    this.props.eightteenChildOneToFather("这是 props 改变父元素的值");
  };

  render() {
    return (
      <div>
        <div>这是通过 props 传入的值{this.props.name}</div>
        <Button type="primary" onClick={this.click}>
          点击改变父元素值
        </Button>
      </div>
    );
  }
}

родительский компонент

<EightteenChildOne name={'props 传入的 name 值'} eightteenChildOneToFather={(mode)=>this.eightteenChildOneToFather(mode)}></EightteenChildOne> 

// 或者
<EightteenChildOne name={'props 传入的 name 值'} eightteenChildOneToFather={this.eightteenChildOneToFather.bind(this)}></EightteenChildOne> 

Когда реквизиты передают несколько значений:
традиционное письмо

const {dataOne,dataTwo,dataThree} = this.state
<Com dataOne={dataOne} dataTwo={dataTwo} dataThree={dataThree}>

обновление письма

<Com {...{dataOne,dataTwo,dataThree}}>

1.2 версия обновления реквизита

Принцип: дочерний компонент использует реквизиты для прямого вызова метода родительского компонента, тем самым изменяя значение родительского компонента.
Примечание. Этот метод похож на реквизит, это применение реквизита, поэтому в исходном коде нет примера.

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

// 父组件
state = {
  count: {}
}
changeParentState = obj => {
    this.setState(obj);
}
// 子组件
onClick = () => {
    this.props.changeParentState({ count: 2 });
}

1.3 Поставщик, потребитель и контекст

1.Context — это глобальный объект, определенный до 16.x, аналогичный eventBus vue, если компонент хочет использовать значение напрямую через this.context.

//根组件
class MessageList extends React.Component {
  getChildContext() {
    return {color: "purple",text: "item text"};
  }

  render() {
    const {messages} = this.props || {}
    const children = messages && messages.map((message) =>
      <Message text={message.text} />
    );
    return <div>{children}</div>;
  }
}

MessageList.childContextTypes = {
  color: React.PropTypes.string
  text: React.PropTypes.string
};

//中间组件
class Message extends React.Component {
  render() {
    return (
      <div>
        <MessageItem />
        <Button>Delete</Button>
      </div>
    );
  }
}

//孙组件(接收组件)
class MessageItem extends React.Component {
  render() {
    return (
      <div>
        {this.context.text}
      </div>
    );
  }
}

MessageItem.contextTypes = {
  text: React.PropTypes.string //React.PropTypes在 15.5 版本被废弃,看项目实际的 React 版本
};

class Button extends React.Component {
  render() {
    return (
      <button style={{background: this.context.color}}>
        {this.props.children}
      </button>
    );
  }
}

Button.contextTypes = {
  color: React.PropTypes.string
};

Контекст после 2.16.x использует режимы Provider и Customer.Значение передается в Provider верхнего уровня, а значение получается в Потребителе дочернего уровня, и функции могут быть переданы для изменения контекста. Объявите определение глобального контекста, context.js

import React from 'react'
let { Consumer, Provider } = React.createContext();//创建 context 并暴露Consumer和Provider模式
export {
    Consumer,
    Provider
}

импорт родительского компонента

// 导入 Provider
import {Provider} from "../../utils/context"

<Provider value={name}>
  <div style={{border:'1px solid red',width:'30%',margin:'50px auto',textAlign:'center'}}>
    <p>父组件定义的值:{name}</p>
    <EightteenChildTwo></EightteenChildTwo>
  </div>
</Provider>

Подсборка

// 导入Consumer
import { Consumer } from "../../utils/context"
function Son(props) {
  return (
    //Consumer容器,可以拿到上文传递下来的name属性,并可以展示对应的值
    <Consumer>
      {name => (
        <div
          style={{
            border: "1px solid blue",
            width: "60%",
            margin: "20px auto",
            textAlign: "center"
          }}
        >
        // 在 Consumer 中可以直接通过 name 获取父组件的值
          <p>子组件。获取父组件的值:{name}</p>
        </div>
      )}
    </Consumer>
  );
}
export default Son;

1.4 EventEmitter

Портал EventEmiterИспользуйте плагин событий, чтобы определить глобальный механизм событий

1.5 Параметры маршрута

1.params

<Route path='/path/:name' component={Path}/>
<link to="/path/2">xxx</Link>
this.props.history.push({pathname:"/path/" + name});
读取参数用:this.props.match.params.name

2.query

<Route path='/query' component={Query}/>
<Link to={{ pathname : '/query' , query : { name : 'sunny' }}}>
this.props.history.push({pathname:"/query",query: { name : 'sunny' }});
读取参数用: this.props.location.query.name

3.state

<Route path='/sort ' component={Sort}/>
<Link to={{ pathname : '/sort ' , state : { name : 'sunny' }}}> 
this.props.history.push({pathname:"/sort ",state : { name : 'sunny' }});
读取参数用: this.props.location.query.state 

4.search

<Route path='/web/search ' component={Search}/>
<link to="web/search?id=12121212">xxx</Link>
this.props.history.push({pathname:`/web/search?id ${row.id}`});
读取参数用: this.props.location.search

В react-router-dom: v4.2.2 есть ошибка, страница перехода будет пустой, и она будет загружена после обновления

5. Преимущества и недостатки

1.params在HashRouter和BrowserRouter路由中刷新页面参数都不会丢失
2.state在BrowserRouter中刷新页面参数不会丢失,在HashRouter路由中刷新页面会丢失
3.query:在HashRouter和BrowserRouter路由中刷新页面参数都会丢失
4.query和 state 可以传对象

1.6 onRef

Принцип: принцип связи onRef заключается в передаче this (экземпляра компонента) компонента в качестве параметра родительскому компоненту через механизм событий реквизита, и родительский компонент может управлять состоянием и методом дочернего компонента.

EightteenChildFour.jsx

export default class EightteenChildFour extends React.Component {
  state={
      name:'这是组件EightteenChildFour的name 值'
  }

  componentDidMount(){
    this.props.onRef(this)
    console.log(this) // ->将EightteenChildFour传递给父组件this.props.onRef()方法
  }

  click = () => {
    this.setState({name:'这是组件click 方法改变EightteenChildFour改变的name 值'})
  };

  render() {
    return (
      <div>
        <div>{this.state.name}</div>
        <Button type="primary" onClick={this.click}>
          点击改变组件EightteenChildFour的name 值
        </Button>
      </div>
    );
  }
}

eighteen.jsx

<EightteenChildFour onRef={this.eightteenChildFourRef}></EightteenChildFour>

eightteenChildFourRef = (ref)=>{
  console.log('eightteenChildFour的Ref值为')
  // 获取的 ref 里面包括整个组件实例
  console.log(ref)
  // 调用子组件方法
  ref.click()
}

1.7 ref

Принцип: получить весь экземпляр подкомпонента через атрибут ref React, а затем управлять им.

EightteenChildFive.jsx

// 常用的组件定义方法
export default class EightteenChildFive extends React.Component {
  state={
      name:'这是组件EightteenChildFive的name 值'
  }

  click = () => {
    this.setState({name:'这是组件click 方法改变EightteenChildFive改变的name 值'})
  };

  render() {
    return (
      <div>
        <div>{this.state.name}</div>
        <Button type="primary" onClick={this.click}>
          点击改变组件EightteenChildFive的name 值
        </Button>
      </div>
    );
  }
}

eighteen.jsx

// 钩子获取实例
componentDidMount(){
    console.log('eightteenChildFive的Ref值为')
      // 获取的 ref 里面包括整个组件实例,同样可以拿到子组件的实例
    console.log(this.refs["eightteenChildFiveRef"])
  }

// 组件定义 ref 属性
<EightteenChildFive ref="eightteenChildFiveRef"></EightteenChildFive>

1.8 redux

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

1.9 MobX

MobX также является независимым плагином для обмена сообщениями о событиях, поэтому я не буду вдаваться в подробности.
Пожалуйста, нажмите на портал:

1.10 flux

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

1.11 hooks

1.hooks должен использовать userReducer и контекст для достижения связи, следующее моделирование реализует простое сокращение
2. Файлы ядра делятся на действия, редьюсеры, типы
action.js

import * as Types from './types';

export const onChangeCount = count => ({
    type: Types.EXAMPLE_TEST,
    count: count + 1
})

reducer.js

import * as Types from "./types";
export const defaultState = {
  count: 0
};
export default (state, action) => {
  switch (action.type) {
    case Types.EXAMPLE_TEST:
      return {
        ...state,
        count: action.count
      };
    default: {
      return state;
    }
  }
};

types.js

export const EXAMPLE_TEST = 'EXAMPLE_TEST';

eightteen.jsx

export const ExampleContext = React.createContext(null);//创建createContext上下文

// 定义组件
function ReducerCom() {
  const [exampleState, exampleDispatch] = useReducer(example, defaultState);

  return (
    <ExampleContext.Provider
      value={{ exampleState, dispatch: exampleDispatch }}
    >
      <EightteenChildThree></EightteenChildThree>
    </ExampleContext.Provider>
  );
}

EightteenChildThree.jsx // компонент

import React, {  useEffect, useContext } from 'react';
import {Button} from 'antd'

import {onChangeCount} from '../../pages/TwoTen/store/action';
import { ExampleContext } from '../../pages/TwoTen/eighteen';

const Example = () => {

    const exampleContext = useContext(ExampleContext);

    useEffect(() => { // 监听变化
        console.log('变化执行啦')
    }, [exampleContext.exampleState.count]);

    return (
        <div>
            <p>值为{exampleContext.exampleState.count}</p>
            <Button onClick={() => exampleContext.dispatch(onChangeCount(exampleContext.exampleState.count))}>点击加 1</Button>
        </div>
    )
}

export default Example;

3. Хуки на самом деле являются инкапсуляцией оригинального API React, предоставляя более удобные в использовании хуки;

4. Крючки бывают:

имя хука эффект
useState Инициализировать и установить состояние
useEffect componentDidMount, componentDidUpdate и componentWillUnmount объединены, поэтому вы можете отслеживать изменения значения, определенного useState.
useContext Определить глобальный объект, аналогичный контексту
useReducer Функции могут быть расширены, чтобы обеспечить функциональность, подобную Redux.
useCallback Функция памяти, есть два параметра, первый параметр — анонимная функция, тело функции, которое мы хотим создать. Второй параметр представляет собой массив, каждый из которых используется для определения того, следует ли пересоздавать переменную тела функции.Если значение переданной переменной остается неизменным, будет возвращен результат памяти. Если какой-либо элемент изменится, верните новый результат
useMemo Функция и входящие параметры такие же, как и useCallback, useCallback возвращает функцию, useDemo возвращает значение
useRef Получить дом, соответствующий атрибуту ref
useImperativeMethods Настройте значение экземпляра, предоставляемое родительскому компоненту при использовании ref
useMutationEffect Работает так же, как useEffect, но срабатывает синхронно на том же этапе, когда React выполняет свои изменения DOM перед обновлением родственных компонентов.
useLayoutEffect Работает так же, как useEffect, но срабатывает синхронно после всех изменений DOM.

5.useImperativeMethods

function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeMethods(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);

1.12 slot

Слот предназначен для передачи метки родительского компонента дочернему компоненту, аналогично v-slot vue.
Сценарий: некоторые компоненты имеют только некоторую общую логику dom, некоторые из которых независимы.

// 父组件文件
import SlotChild from 'SlotChild'

<SlotChild
slot={<div>这是父组件的 slot</div>}>
</SlotChild>

// 子组件
子组件直接获取 this.props.slot 就可获取到内容

1.13 Сравнение

метод преимущество недостаток
props Нет необходимости вводить внешние плагины Для связи между компонентами Brother необходимо установить общий родительский компонент, что создает проблемы.
обновление реквизита Нет необходимости вводить внешние плагины, от ребенка к родителю, нет необходимости получать метод в родительском компоненте с реквизитом
Поставщик, потребитель и контекст Нет необходимости вводить внешние плагины, инструмент для связи между многоуровневыми компонентами или родственными компонентами. Проблема с отслеживанием состояния данных о состоянии
EventEmitter Может поддерживать связь между компонентами брата и родителя-ребенка. Импорт внешних плагинов
параметры маршрутизации Он может поддерживать одноуровневые компоненты для передачи значений, а простая передача данных страницы очень удобна. Связь между родительскими и дочерними компонентами бессильна
onRef Вы можете получить весь экземпляр подкомпонента, используя простой Связь компонентов Brother проблематична, официальная не рекомендует использовать
ref то же, что и по ссылке то же, что и по ссылке
redux Установлен глобальный государственный менеджер, и связь между братьями и сыновьями может быть решена. Введены внешние плагины
mobx Установлен глобальный государственный менеджер, и связь между братьями и сыновьями может быть решена. Введены внешние плагины
flux Установлен глобальный государственный менеджер, и связь между братьями и сыновьями может быть решена. Введены внешние плагины
hooks 16.x новые свойства, могут поддерживать одноуровневую связь, связь между родительскими и дочерними компонентами Необходимо использовать в сочетании с контекстом
slot Поддержка передачи тегов от родителя к дочернему

Сравнение Redux, mobx и flux

метод представлять
redux 1. Базовые модули: Action, Reducer, Store 2. Логика хранения и изменения разделена 3. Есть только один Store 4. Один Store с иерархическими редьюсерами 5. Нет понятия планировщика 6. Контейнерные компоненты Связь есть 7. Состояние неизменяемое 8. Больше следовать идее функционального программирования
mobx 1. Основные модули: Action, Reducer, Derivation 2. Имеется несколько хранилищ 3. Дизайн больше склонен к объектно-ориентированному программированию и реактивному программированию, обычно оборачивая состояние в наблюдаемый объект, и как только объект состояния изменяется, можно автоматически получать обновления
flux 1. Основные модули: Store, ReduceStore, Container 2. Есть несколько магазинов;

2.require.context()

Это API веб-пакета, который представлен в навыках vue, потому что проекты Vue и React упакованы на основе веб-пакета, поэтому их также можно использовать в реакции.

const path = require('path')
const files = require.context('@/components/home', false, /\.vue$/)
const modules = {}
files.keys().forEach(key => {
  const name = path.basename(key, '.vue')
  modules[name] = files(key).default || files(key)
})

3.Decorator

Определение: декоратор — это новая функция ES7, которая может изменять свойства класса.

import React from 'react'
import Test from '../../utils/decorators'

@Test
//只要Decorator后面是Class,默认就已经把Class当成参数隐形传进Decorator了。
class TwentyNine extends React.Component{
    componentDidMount(){
        console.log(this,'decorator.js') // 这里的this是类的一个实例
        console.log(this.testable)
    }
    render(){
        return (
            <div>这是技巧23</div>
        )
    }
}

export default TwentyNine

decorators.js

function testable(target) {
  console.log(target)
  target.isTestable = true;
  target.prototype.getDate = ()=>{
    console.log( new Date() )
  }
}

export default testable

Многие промежуточные программы, такие как redux, инкапсулируют использование Decorator.

4. Используйте если... еще

Сценарий: иногда необходимо отобразить различный контент в соответствии с разными страницами значений статуса.

import React from "react";

export default class Four extends React.Component {
  state = {
    count: 1
  };
  render() {
    let info
    if(this.state.count===0){
      info=(
        <span>这是数量为 0 显示</span>
      )
    } else if(this.state.count===1){
      info=(
        <span>这是数量为 1 显示</span>
      )
    }
    return (
      <div>
        {info}
      </div>
    );
  }
}

5. Пять способов изменить значение состояния

способ 1

let {count} = this.state
this.setState({count:2})

Способ 2: обратный вызов

this.setState(({count})=>({count:count+2}))

Способ 3: получение параметров состояния и реквизита

this.setState((state, props) => {
    return { count: state.count + props.step };
});

Способ 4: крючки

const [count, setCount] = useState(0)
// 设置值
setCount(count+2)

Способ 5: вызывается после изменения значения состояния

this.setState(
    {count:3},()=>{
        //得到结果做某种事
    }
)

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

Используйте componentWillReceiveProps до 1.16.x

componentWillReceiveProps (nextProps){
  if(this.props.visible !== nextProps.visible){
      //props 值改变做的事
  }
}

Примечание: иногда componentWillReceiveProps будет срабатывать, даже если значение реквизита не изменилось, потому что он не будет вызываться после первого рендеринга жизненного цикла, а будет вызываться при каждом последующем рендеринге = когда родительский компонент снова отправляет реквизит.

Используйте getDerivedStateFromProps после 2.16.x, а componentWillReveiveProps не удаляется после 16.x.

export default class Six extends React.Component {
  state = {
    countOne:1,
    changeFlag:''
  };
  clickOne(){
    let {countOne} = this.state
    this.setState({countOne:countOne+1})
  };
  static getDerivedStateFromProps (nextProps){
    console.log('变化执行')
    return{
      changeFlag:'state 值变化执行'
    }
  }
  render() {
    const {countOne,changeFlag} = this.state
    return (
      <div>
        <div>
         <Button type="primary" onClick={this.clickOne.bind(this)}>点击加 1</Button><span>countOne 值为{countOne}</span>
        <div>{changeFlag}</div>
        </div>
      </div>
    );
  }
}

7. Метод определения компонента

Метод 1: определение функции ES5

function FunCom(props){
  return <div>这是Function 定义的组件</div>
}
ReactDOM.render(<FunCom name="Sebastian" />, mountNode)

// 在 hooks 未出来之前,这个是定义无状态组件的方法,现在有了 hooks 也可以处理状态

Метод 2: определение createClass в ES5

const CreateClassCom = React.createClass({
  render: function() {
  return <div>这是React.createClass定义的组件</div>
  }
});

Подход 3: ES6 расширяется

class Com extends React.Component {
  render(){
    return(<div>这是React.Component定义的组件</div>)
  }
}

передача

export default class Seven extends React.Component {
  render() {
    return (
      <div>
        <FunCom></FunCom>
        <Com></Com>
      </div>
    );
  }
}

Отличие: createClass ES5 — это es6, созданный с использованием функции для имитации написания класса; Компонент создан по атрибуту нового класса es6 Этот компонент легко создать.

8. Получить компонент через атрибут ref

Метод 1: Это также самое раннее использование, полученное через this.refs[имя свойства] Также может воздействовать на компоненты для получения экземпляров компонентов.

class RefOne extends React.Component{
  componentDidMount() {
    this.refs['box'].innerHTML='这是 div 盒子,通过 ref 获取'
  }
  render(){
    return(
      <div ref="box"></div>
    )
  }
}

Метод 2: Функция обратного вызова, смонтируйте функцию на узле или компоненте dom, входным параметром функции является экземпляр узла или компонента dom, достигнутый эффект такой же, как и в строковой форме, все должны получить его ссылку

class RefTwo extends React.Component{
  componentDidMount() {
    this.input.value='这是输入框默认值';
    this.input.focus();
  }
  render(){
    return(
      <input ref={comp => { this.input = comp; }}/>
    )
  }
}

Способ 3: React.createRef() После React 16.3 используйте этот метод для создания ссылки. Назначьте его переменной и смонтируйте на узле или компоненте dom через ref.Текущий атрибут ref сможет получить экземпляр узла или компонента dom.

class RefThree extends React.Component{
  constructor(props){
    super(props);
    this.myRef=React.createRef();
  }
  componentDidMount(){
    console.log(this.myRef.current);
  }
  render(){
    return <input ref={this.myRef}/>
  }
}

Способ 4: React.forwardRef
Предоставляется после React 16.3, может использоваться для создания дочерних компонентов для передачи ref

class RefFour extends React.Component{
  constructor(props){
    super(props);
    this.myFourRef=React.forwardRef();
  }
  componentDidMount(){
    console.log(this.myFourRef.current);
  }
  render(){
    return <Child ref={this.myFourRef}/>
  }
}

Подкомпоненты создаются с помощью React.forwardRef, а ссылки могут передаваться внутренним узлам или компонентам для получения межуровневых ссылок. forwardRef может получить экземпляр исходного компонента в компоненте более высокого порядка.Эта функция будет подчеркнута в Совете 18.

9.статическое использование

Сценарий: ключевое слово для объявления статического метода, статический метод означает, что его можно вызвать напрямую, даже если нет экземпляра компонента.

export default class Nine extends React.Component {
  static update(data) {
    console.log('静态方法调用执行啦')
  }
  render() {
    return (
      <div>
        这是 static 关键字技能
      </div>
    );
  }
}

Nine.update('2')

Уведомление: 1. Класс ES6, когда мы определяем компонент, мы обычно определяем класс, а static создает свойство или метод, принадлежащий этому классу.
2. Компонент является экземпляром этого класса, а свойства и состояние компонента принадлежат этому экземпляру, поэтому экземпляр еще не создан
3. Итак, static не определяется реакцией, и добавление ключевого слова static означает, что метод не будет унаследован экземпляром, а будет вызываться напрямую через класс, поэтому доступ к этому невозможен.
4. getDerivedStateFromProps также прослушивает значения с помощью статических методов.Подробности см. в Навыке 6.

10.конструктор и супер

рассмотрение:
1. Прежде чем говорить об этих двух свойствах, давайте просмотрим метод определения функции ES6
2. Каждый класс, определенный с помощью метода класса, по умолчанию имеет функцию-конструктор, эта функция является основной функцией конструктора, а this внутри тела функции указывает на сгенерированный экземпляр.
3. Ключевое слово super используется для доступа и вызова функций родительского объекта объекта.

export default class Ten extends React.Component {
  constructor() { // class 的主函数
    super() // React.Component.prototype.constructor.call(this),其实就是拿到父类的属性和方法
    this.state = {
      arr:[]
    }
  }  
  render() {
    return (
      <div>
        这是技巧 10
      </div>
    );
  }
}

11.PropTypes

Сценарий: определение типа данных входящих подкомпонентов
Проверка типов PropTypes устарела, начиная с React v15.5, используйте prop-types
Способ 1: Старый способ письма

class PropTypeOne extends React.Component {
  render() {
    return (
      <div>
        <div>{this.props.email}</div>
        <div>{this.props.name}</div>
      </div>
    );
  }
}

PropTypeOne.propTypes = {
  name: PropTypes.string, //值可为array,bool,func,number,object,symbol
  email: function(props, propName, componentName) { //自定义校验
    if (
      !/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/.test(
        props[propName]
      )
    ) {
      return new Error(
        "组件" + componentName + "里的属性" + propName + "不符合邮箱的格式"
      );
    }
  },
};

Способ 2: используйте статические свойства ключевого слова ES7 Static

class PropTypeTwo extends React.Component {
  static propTypes = {
      name:PropTypes.string
  };
  render() {
    return (
      <div>
        <div>{this.props.name}</div>
      </div>
    );
  }
}

12. Используйте синтаксис объявления поля класса

Сценарий: локальное состояние можно инициализировать без конструктора, а методы класса можно объявлять с помощью стрелочных функций без дополнительной привязки к ним.

class Counter extends Component {
  state = { value: 0 };

  handleIncrement = () => {
    this.setState(prevState => ({
      value: prevState.value + 1
    }));
  };

  handleDecrement = () => {
    this.setState(prevState => ({
      value: prevState.value - 1
    }));
  };

  render() {
    return (
      <div>
        {this.state.value}

        <button onClick={this.handleIncrement}>+</button>
        <button onClick={this.handleDecrement}>-</button>
      </div>
    )
  }
}

13. Асинхронные компоненты

1. Сценарий: переключение маршрутов, если несколько маршрутов страниц загружаются синхронно, это приведет к замедлению

2. Основной API:
загрузчик: компонент, который необходимо загрузить
загрузка: компоненты отображения страницы, которые не загружены
задержка: отложить время загрузки
тайм-аут: тайм-аут

3. Как использовать:
Установить react-loadable, установка плагина babel синтаксис-динамический-импорт.

const Loading = () => {
  return <div>loading</div>;
};

const LoadableComponent = Loadable({
  loader: () => import("../../components/TwoTen/thirteen"),
  loading: Loading
});

export default class Thirteen extends React.Component {
  render() {
    return <LoadableComponent></LoadableComponent>;
  }
}

4.Loadable.Map()
Компоненты более высокого порядка, которые загружают несколько ресурсов параллельно

14. Динамические компоненты

Сценарий: при переключении вкладок задействована динамическая загрузка компонентов.
По сути, он использует тернарное выражение, чтобы определить, отображается ли компонент.

class FourteenChildOne extends React.Component {
    render() {
        return <div>这是动态组件 1</div>;
    }
}

class FourteenChildTwo extends React.Component {
    render() {
        return <div>这是动态组件 2</div>;
    }
}

export default class Fourteen extends React.Component {
  state={
      oneShowFlag:true
  }
  tab=()=>{
      this.setState({oneShowFlag:!this.state.oneShowFlag})
  }
  render() {
    const {oneShowFlag} = this.state
    return (<div>
        <Button type="primary" onClick={this.tab}>显示组件{oneShowFlag?2:1}</Button>
        {oneShowFlag?<FourteenChildOne></FourteenChildOne>:<FourteenChildTwo></FourteenChildTwo>}
    </div>);
  }
}

Если это один компонент, может ли дисплей использовать операцию короткого замыкания

oneShowFlag&&<FourteenChildOne></FourteenChildOne>

15. Рекурсивные компоненты

Сценарий: компонент дерева
Оберните цикл с помощью React.Fragment или div

class Item extends React.Component {
  render() {
    const list = this.props.children || [];
    return (
      <div className="item">
        {list.map((item, index) => {
          return (
            <React.Fragment key={index}>
              <h3>{item.name}</h3>
              {// 当该节点还有children时,则递归调用本身
              item.children && item.children.length ? (
                <Item>{item.children}</Item>
              ) : null}
            </React.Fragment>
          );
        })}
      </div>
    );
  }
}

16. Контролируемые и неконтролируемые компоненты

Контролируемый компонент: состояние компонента контролируется состоянием значения состояния React или реквизитами.

class Controll extends React.Component {
  constructor() {
    super();
    this.state = { value: "这是受控组件默认值" };
  }
  render() {
    return <div>{this.state.value}</div>;
  }
}

Неуправляемые компоненты: компоненты не контролируются значениями состояния React и контролируются функциями dom или ссылками React.

class NoControll extends React.Component {
  render() {
    return <div>{this.props.value}</div>;
  }
}

код импорта:

export default class Sixteen extends React.Component {
  componentDidMount() {
    console.log("ref 获取的不受控组件值为", this.refs["noControll"]);
  }
  render() {
    return (
      <div>
        <Controll></Controll>
        <NoControll
          value={"这是不受控组件传入值"}
          ref="noControll"
        ></NoControll>
      </div>
    );
  }
}

17. Компоненты высшего порядка (HOC)

17.1 Определения

1. Это похоже на определение функции высшего порядка, принимающей компонент в качестве параметра или возвращающей компонент компонента;
2. Функция:
Извлечение повторяющегося кода, реализация повторного использования компонентов, общих сценариев и повторного использования страниц;
Условный рендеринг, управление логикой рендеринга компонентов (перехват рендеринга), общие сценарии, контроль разрешений;
Захват/перехват жизненного цикла обработанного компонента, общие сценарии, отслеживание производительности рендеринга компонентов, управление журналами

17.2 Метод реализации

1. Агент по недвижимости

import React,{Component} from 'react';

const Seventeen = WrappedComponent =>
  class extends React.Component {
    render() {
      const props = {
        ...this.props,
        name: "这是高阶组件"
      };
      return <WrappedComponent {...props} />;
    }
  };

class WrappedComponent extends React.Component {
  state={
     baseName:'这是基础组件' 
  }
  render() {
    const {baseName} = this.state
    const {name} = this.props
    return <div>
        <div>基础组件值为{baseName}</div>
        <div>通过高阶组件属性代理的得到的值为{name}</div>
    </div>
  }
}

export default Seventeen(WrappedComponent)

2. Обратное наследование
Принцип состоит в том, чтобы использовать супер, чтобы изменить это направление компонента, а затем вы можете обработать некоторые значения компонента контейнера в компоненте

  const Seventeen = (WrappedComponent)=>{
    return class extends WrappedComponent {
        componentDidMount() {
            this.setState({baseName:'这是通过反向继承修改后的基础组件名称'})
        }
        render(){
            return super.render();
        }
    }
}

class WrappedComponent extends React.Component {
  state={
     baseName:'这是基础组件' 
  }
  render() {
    const {baseName} = this.state
    return <div>
        <div>基础组件值为{baseName}</div>
    </div>
  }
}

export default Seventeen(WrappedComponent);

18. Отображается ли элемент

Обычно используйте троичные выражения

 flag?<div>显示内容</div>:''
 flag&&<div>显示内容</div>

19. Создание диалогового компонента

Диалог должен быть наиболее часто используемым компонентом. Ниже приведены три различных метода создания. Способ 1: контролировать, отображается ли компонент через состояние

 class NineteenChildOne extends React.Component {
  render() {
    const Dialog = () => <div>这是弹层1</div>;

    return this.props.dialogOneFlag && <Dialog />;
  }
}

Способ 2: Создать эластичный слой через ReactDom.render — смонтировать внешний слой корневого узла
Элемент CreateElement, управляемый нативным, appendChild, removeChild и реагирует на ReactDOM.render, ReactDOM.unmountComponentAtNode, показывает и скрывает

NineteenChild.jsx

import ReactDOM from "react-dom";

class Dialog {
  constructor(name) {
    this.div = document.createElement("div");
    this.div.style.width = "200px";
    this.div.style.height = "200px";
    this.div.style.backgroundColor = "green";
    this.div.style.position = "absolute";
    this.div.style.top = "200px";
    this.div.style.left = "400px";
    this.div.id = "dialog-box";
  }
  show(children) {
    // 销毁
    const dom = document.querySelector("#dialog-box");
    if(!dom){ //兼容多次点击
      // 显示
      document.body.appendChild(this.div);
      ReactDOM.render(children, this.div);
    }
  }
  destroy() {
    // 销毁
    const dom = document.querySelector("#dialog-box");
    if(dom){//兼容多次点击
      ReactDOM.unmountComponentAtNode(this.div);
      dom.parentNode.removeChild(dom);
    }
  }
}
export default {
  show: function(children) {
    new Dialog().show(children);
  },
  hide: function() {
    new Dialog().destroy();
  }
};

nineteen.jsx

twoSubmit=()=>{
    Dialog.show('这是弹层2')
  }

  twoCancel=()=>{
    Dialog.hide()
  }

20.React.memo

Действие: когда компоненты класса входных атрибутов одинаковы, могут быть использованы, чтобы избежать рендеринга надоводокомендующую PUREComponent или сборку. Теперь вы можете отреагировать. Мэмо в достижение той же функции функцией компонента упаковки

import React from "react";

function areEqual(prevProps, nextProps) {
  /*
  如果把 nextProps 传入 render 方法的返回结果与
  将 prevProps 传入 render 方法的返回结果一致则返回 true,
  否则返回 false
  */
  if (prevProps.val === nextProps.val) {
    return true;
  } else {
    return false;
  }
}

// React.memo()两个参数,第一个是纯函数,第二个是比较函数
export default React.memo(function twentyChild(props) {
  console.log("MemoSon rendered : " + Date.now());
  return <div>{props.val}</div>;
}, areEqual);

21.React.PureComponent

эффект:
1.React.PureComponent похож на React.Component, оба определяют класс компонента.
2. Разница в том, что React.Component не реализует shouldComponentUpdate(), а React.PureComponent реализует его посредством поверхностного сравнения свойств и состояния.
3.React.PureComponent работает в классах, а React.memo работает в функциях.
4. Если пропсы и состояние компонента одинаковые, содержимое рендера тоже такое же, то можно использовать React.PureComponent, который может повысить производительность компонента

class TwentyOneChild extends React.PureComponent{  //组件直接继承React.PureComponent
  render() {
    return <div>{this.props.name}</div>
  }
}

export default class TwentyOne extends React.Component{
    render(){
        return (
            <div>
              <TwentyOneChild name={'这是React.PureComponent的使用方法'}></TwentyOneChild>
            </div>
        )
    }
}

22.React.Component

Функция: это компонент React, основанный на классе ES6. React позволяет определить класс или функцию как компонент. Чтобы определить класс компонента, вам необходимо наследовать React.Component

export default class TwentyTwo extends React.Component{ //组件定义方法
    render(){
        return (
            <div>这是技巧22</div>
        )
    }
}

23. Вывести значение FALSY в JSX

определение:
1. Ложное значение (ложное значение) — это значение, которое считается ложным в логическом контексте;
2. Значения: 0, "",'',``,null,undefined,NaN

export default class TwentyThree extends React.Component{
    state={myVariable:null}
    render(){
        return (
            <div>{String(this.state.myVariable)}</div>
        )
    }
}

Если фиктивное значение отображается напрямую, оно будет неявно преобразовано в false, поэтому страница отображаться не будет.

24.ReactDOM.createPortal

Функция: элемент, возвращаемый функцией рендеринга компонента, будет смонтирован на его родительском компоненте. createPortal предоставляет отличное решение для рендеринга дочерних узлов в узлы DOM, которые существуют вне родительского компонента.

import React from "react";
import ReactDOM from "react-dom";
import {Button} from "antd"

const modalRoot = document.body;

class Modal extends React.Component {
  constructor(props) {
    super(props);
    this.el = document.createElement("div");
    this.el.style.width = "200px";
    this.el.style.height = "200px";
    this.el.style.backgroundColor = "green";
    this.el.style.position = "absolute";
    this.el.style.top = "200px";
    this.el.style.left = "400px";
  }

  componentDidMount() {
    modalRoot.appendChild(this.el);
  }

  componentWillUnmount() {
    modalRoot.removeChild(this.el);
  }

  render() {
    return ReactDOM.createPortal(this.props.children, this.el);
  }
}

function Child() {
  return (
    <div className="modal">
      这个是通过ReactDOM.createPortal创建的内容
    </div>
  );
}

export default class TwentyFour extends React.Component {
  constructor(props) {
    super(props);
    this.state = { clicks: 0 };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState(prevState => ({
      clicks: prevState.clicks + 1
    }));
  }

  render() {
    return (
      <div>
          <Button onClick={this.handleClick}>点击加1</Button>
        <p>点击次数: {this.state.clicks}</p>
        <Modal>
          <Child />
        </Modal>
      </div>
    );
  }
}

Это добавит элемент к указанному элементу.

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

Сценарий: некоторые фоновые возвраты являются полями формата html, вам нужно использовать свойство innerHTML

export default class TwentyFive extends React.Component {
  render() {
    return (
      <div dangerouslySetInnerHTML={{ __html: "<span>这是渲染的 HTML 内容</span>" }}></div>
    );
  }
}

26.React.createElement

грамматика:
React.createElement( type, [props], [...children] )

Исходный код:

export default class TwentySix extends React.Component {
  render() {
    return (
      <div>
        {React.createElement(
          "div",
          { id: "one", className: "two" },
          React.createElement("span", { id: "spanOne" }, "这是第一个 span 标签"),
          React.createElement("br"),
          React.createElement("span", { id: "spanTwo" }, "这是第二个 span 标签")
        )}
      </div>
    );
  }
}

Принцип: по сути, dom JSX окончательно преобразуется в js с помощью React.createElement.

// jsx 语法
<div id='one' class='two'>
    <span id="spanOne">this is spanOne</span>
    <span id="spanTwo">this is spanTwo</span>
</div>

// 转化为 js
React.createElement(
  "div",
 { id: "one", class: "two" },
 React.createElement( "span", { id: "spanOne" }, "this is spanOne"), 
 React.createElement("span", { id: "spanTwo" }, "this is spanTwo")
);

27.React.cloneElement

грамматика:

React.cloneElement(
  element,
  [props],
  [...children]
)

Роль: Роль этого метода заключается в копировании компонента, передаче значений компоненту или добавлении свойств.
Основной код

React.Children.map(children, child => {
  return React.cloneElement(child, {
    count: _this.state.count
  });
});

28.React.Fragment

Роль: React.Fragment позволяет вам агрегировать список дочерних элементов без добавления дополнительных узлов в DOM.
основной код

render() {
    const { info } = this.state;
    return (
      <div>
        {info.map((item, index) => {
          return (
            <React.Fragment key={index}>
              <div>{item.name}</div>
              <div>{item.age}</div>
            </React.Fragment>
          );
        })}
      </div>
    );
  }

29. Петлевые элементы

Нет внутренней инкапсуляции инструкций типа v-for в vue, но обход осуществляется через map

{arr.map((item,index)=>{
  return(
    <div key={item.id}>
      <span>{item.name}</span>
      <span>{item.age}</span>
    </div>
  )
})}

30. Установите и получите пользовательские свойства в DOM

Роль: некоторым нужно передавать значения через пользовательские атрибуты

export default class Thirty extends React.Component {
  click = e => {
    console.log(e.target.getAttribute("data-row"));
  };

  render() {
    return (
      <div>
        <div data-row={"属性1"} data-col={"属性 2"} onClick={this.click}>
          点击获取属性
        </div>
      </div>
    );
  }
}

31. Обязательные события

Сценарий: взаимодействие будет включать клики по событиям, а затем щелчок по выбранному значению для передачи параметров также является очень распространенным сценарием.

import React from "react";
import { Button } from 'antd'

export default class Three extends React.Component {
  state = {
    flag: true,
    flagOne: 1
  };
  click(data1,data2){
    console.log('data1 值为',data1)
    console.log('data2 值为',data2)
  }
  render() {
    return (
      <div>
        <Button type="primary" onClick={this.click.bind(this,'参数 1','参数 2')}>点击事件</Button>
      </div>
    );
  }
}

Метод использования подробно описан в исходном коде route.js.

32.React-Router

32.1 Различия между V3 и V4

1. V3 или более ранние версии отдельных компонентов маршрутизатора и макета V;
2. V4 — это централизованный маршрутизатор, который реализует вложение макета и страницы посредством вложения маршрута, а компоненты макета и страницы являются частью маршрутизатора;
3. Правило маршрутизации в V3 является исключительным, что означает, что в итоге получается только один маршрут;
4. Маршруты в V4 являются инклюзивными, что означает несколько, могут совпадать и присутствовать одновременно.Если вы просто хотите сопоставить маршрут, вы можете использовать переключатель, будет отображаться только один, в то же время может быть в каждом route Add Exact для точного сопоставления Перенаправление, перенаправление браузера, если нет совпадения, совпадение

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

import { HashRouter as Router, Switch  } from "react-router-dom";

class App extends React.Component{
    render(){
        const authPath = '/login' // 默认未登录的时候返回的页面,可以自行设置
        let authed = this.props.state.authed || localStorage.getItem('authed') // 如果登陆之后可以利用redux修改该值
        return (
            <Router>
                <Switch>
                    {renderRoutes(routes, authed, authPath)}
                </Switch>
            </Router>
        )
    }
}

V4 реализует вложение макетов и страниц через вложение маршрутов, а коммутатор переключает роль маршрутизации.

33. Метод введения стиля

Способ 1: импорт импорт

import './App.css';

Метод 2: встроенный метод

import React from 'react';

const Header = () => {

    const heading = '头部组件'

    return(
        <div style={{backgroundColor:'orange'}}>
            <h1>{heading}</h1>
        </div>
    )
}

或者
import React from 'react';

const footerStyle = {
    width: '100%',
    backgroundColor: 'green',
    padding: '50px',
    font: '30px',
    color: 'white',
    fontWeight: 'bold'
}

export const Footer = () => {
    return(
        <div style={footerStyle}>
            底部组件
        </div>
    )
}

34. Имя класса динамической привязки

Принцип: значение класса управления через тройное выражение

render(){
  const flag=true
  return (
    <div className={flag?"active":"no-active"}>这是技巧 34</div>
  )
}

Суммировать

Это 34 навыка React, полученные в результате фактической разработки проекта;
адрес источника,пожалуйста ткнитеприветственная звезда