Обучение React (5) — данные компонентов в React — реквизит

JavaScript React.js

React学习(5)-React组件中的数据-props.png

предисловие

Разработка приложения React больше связана с написанием компонентов, и наименьшая единица компонентов React — это элемент React, а самым большим преимуществом написания компонентов является повторное использование кода.

Разделите большое приложение на несколько частей (компонентов) в соответствии с функциональной структурой, управляйте каждой частью (компонентом) отдельно и объединяйте вещи, связанные с компонентами, для достижения цели высокой сплоченности, а различные компоненты имеют свои собственные достижения независимого управления. Эффект низкой связи.

Сборка компонента это по сути написание javascript функции, а самое главное в компоненте это данные.В React данные делятся на два типа: props и state.При определении компонента он получает произвольные параметры (т.е. props) и использует для возврата элементов React, которые описывают, что страница должна отображать

Независимо от свойств или состояния, когда любой из них изменяется, это вызовет повторный рендеринг функции рендеринга.

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

Итак, при написании компонента React, когда использовать состояние и когда использовать свойства, как разделить данные состояния компонента?

Тогда этот раздел - то, что вы хотите знать

Data-props компонентов в React

реквизит в React

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

Этот полученный объект является реквизитом (сокращение от свойства),Props — это набор свойств, определяемых компонентом, это внешний интерфейс компонента, который передается и задается извне через свойство JSX (то есть данные, передаваемые извне во внутренний компонент).

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

Реагируйте каждый определенный компонент должен существовать независимо от всех модулей, все внешний мир (сборка), внешний мир (сборка) должен участвовать в диалоге и компонентах, отличных от передачи данных через монтажу

В React вы можете обращаться с реквизитами как с атрибутами элементов HTML-тегов., но значения атрибутов нативных тегов HTML — это все строки, даже если они являются встроенными выражениями js, они все равно являются строками, иВ React тип значения свойства prop может быть любым типом данных (базовый тип данных (числовые, строковые, нулевые и т. д. функции) или объект)

Конечно, еслиДля нестроковых типов данных в JSX необходимо заключить значение свойства в фигурные скобки {}

Вот почему стиль имеет два слоя фигурных скобок: самый внешний слой представляет синтаксис JSX, что означает, что это переменный объект, а внутренние фигурные скобки {} представляют объект

В пользовательском компоненте объявления функции, вы можете получить свойства компонента через реквизиты

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

组件的props数据.png

import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';

// 函数式组件,定义一个Button组件,首字母大写
function Button(props) {
  console.log(props); // 将会把调用处组件的style属性给打印出来
  const btnStyles = {
  width: props.style.width,
  height: props.style.height,
  background: props.style.background,
  color: props.style.color,
  border: props.style.border,
  outline: props.style.outline,
  cursor: props.style.cursor
};
return (
  <div>
    <button style = { btnStyles }>按钮</button>
  </div>
);
}

const btnStyle = {
  width: "100px",
  height: "40px",
  background: "orange",
  color: "#fff",
  border: "none",
  outline: "none",
  cursor: "pointer"
}
const container = document.getElementById('root');

ReactDOM.render(<Button style = { btnStyle } />, container);

Компонент, объявленный классом class: реализовано путем наследования React.Component через объявление класса в Es6.

import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';

// 类组件,通过class关键字声明使用
class Button extends Component {
  constructor(props){
  super(props);

}

render() {
  console.log(this.props);
  // 这里利用Es6中的解构赋值
  const { width, height, background, color, border, outline,cursor} = this.props.style;
  const btnStyles = {
    width,  // 等于width:width
    height,
    background,
    color,
    border,
    outline,
    cursor
}
return (
<div>
   <button style = { btnStyles }>按钮</button>
</div>
);
}
}
// 该Button组件按钮自身拥有的属性
const btnStyle = {
  width: "100px",
  height: "40px",
  background: "orange",
  color: "#fff",
  border: "none",
  outline: "none",
  cursor: "pointer"
}

const container = document.getElementById('root');

ReactDOM.render(<Button style = { btnStyle } />, container);

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

Следует, что,Родительский компонент (внешний компонент) передает значение дочернему (внутреннему) компоненту путем установки свойства JSX, а данные родительского (внешнего) компонента получаются внутри дочернего компонента через this.props, что тоже можно считать таковым, props — это интерфейс данных, предоставляемый извне.

Для компонентов, объявленных с классом class, значение read prop получается через this.props

Сначала определите конструктор с помощью конструктора и дайте ему параметр props, а затем вызовите super (props) в функции конструктора конструктора.

Это фиксированный способ записи, компонент наследует некоторые методы родительского класса,Если компонент должен определить свой собственный конструктор, то он должен позвонить супер (реквизит), то есть наследует React.component конструктор

Что касается того, почему вам нужно вызвать метод super(props), потому что Es6 использует его, чтобы сначала создать экземпляр родительского класса, а затем использовать конструктор подкласса для изменения этого

Если нет функции-конструктора-конструктора, вызывающей super() и реквизиты параметров, он сообщит об ошибке.

После создания экземпляра компонента все функции-члены компонента не могут получить доступ к значению реквизита, переданному родительским компонентом через this.props, ошибка выглядит следующим образом.

ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor

О функции конструктораstructor()

Этот конструктор (props) функция-конструктор генерируется автоматически. Если он не объявлен, React по умолчанию добавит пустой конструктор, и он будет выполнен автоматически. Он выполняется только один раз. Его можно рассматривать как функцию-ловушку (жизненный цикл функция)

Эта функция-конструктор получает параметр props и набор значений, переданных внешним компонентом.Пока значение props используется внутри компонента, параметр props должен быть передан, иначе this.props нельзя использовать в текущем компонент для получения прохода внешнего компонента.

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

constructor(props){
   super(props);
}

Что касается функции конструктора без записи, то если пользовательский компонент не нуждается в инициализации State, не используя привязку метода (ЭТО плохие настройки), в качестве отображения используются только простые данные PROPS для получения внешних компонентов, нет взаимодействия с UI рендеринг действия

тогда нет необходимости реализовывать конструктор для этого компонента React

Если это так, его следует преобразовать в функциональный компонент (интерфейс без сохранения состояния), поскольку он наиболее эффективен.

В противном случае необходимо писать функцию конструктора конструктора, а способ написания классов в Es6 дает более практичные функции, при определенных условиях его следует использовать.

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

  • Инициализировать состояние (state) внутри текущего компонента, назначив объект this.state

Не вызывайте метод setState() в функции конструктора().Если компоненту необходимо использовать внутреннее состояние состояния, напрямую присвойте начальное значение состояния this.state в конструкторе.

constructor(props){
  super(props);

  // 不要在这里调用this.setState(),更改state状态数据
  this.state = {
   // 属性:属性值
   count: 0
  }
  //this.方法 = this.方法.bind(this);
   this.handleClick = this.handleClick.bind(this)
}

Вы можете присвоить this.state только непосредственно в конструкторе, если вам нужно изменить значение состояния в других методах, вы должны вместо этого использовать метод this.setState()

Уведомление:

Если вы замените компонент функции на метод записи компонента класса, когда значение внешнего реквизита будет получено внутри подкомпонента,Нужно изменить пропс на this.props, и наоборот, при замене компонента, объявленного классом, на функциональный (без сохранения состояния) компонент, нужно заменить this.props на пропс

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

Не меняйте легко значение в this.props. Другими словами, свойство props компонента доступно только для чтения и не может изменять свои собственные свойства. Это не различает, является ли это компонентом, объявленным с помощью функции, или компонентом, объявленным с class.Это не может быть напрямую Изменить значение реквизита

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

import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';

// 类组件
class Button extends Component {
  constructor(props){
   super(props);

  }

render() {
  const { width, height, background, color, border, outline,cursor} = this.props.style;
  const btnStyles = {
    width,
    height,
    background,
    color,
    border,
    outline,
    cursor
}
return (
  <div>
    <button onClick = { this.handleBtnClick.bind(this) } style = { btnStyles }>{ this.props.btnContent }</button>
  </div>
);
}

handleBtnClick(){
   // 直接更改props的值,是会报错的,在React中不允许这么做
   this.props.btnContent = "按钮B";
}
}

const btnStyle = {
  width: "100px",
  height: "40px",
  background: "orange",
  color: "#fff",
  border: "none",
  outline: "none",
  cursor: "pointer"
}
const container = document.getElementById('root');

ReactDOM.render(<Button btnContent ="按钮A" style = { btnStyle } />, container);

无法更改props的值.png
Поскольку в React поток данных является односторонним, вы не можете изменить пропсы, передаваемые при рендеринге компонента.

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

Но это не значит, что значение props нельзя изменить, иногда из-за бизнес-требований нам нужно изменить значение props.

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

Изменения заключаются в следующем:

import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';

// 类组件
class Button extends Component {
  constructor(props){
    super(props);
    // state是组件内部的状态
    this.state = {
       btnContent: this.props.btnContent
    }

}

render() {
const { width, height, background, color, border, outline,cursor} = this.props.style;
const btnStyles = {
  width,
  height,
  background,
  color,
  border,
  outline,
  cursor
}
return (
   <div>
     <button onClick = { this.handleBtnClick.bind(this) } style = { btnStyles }>{ this.state.btnContent }</button>
   </div>
);
}

handleBtnClick(){
   // this.props.btnContent = "按钮B";
   this.setState({
     btnContent: "按钮B"
   });
}
}

const btnStyle = {
  width: "100px",
  height: "40px",
  background: "orange",
  color: "#fff",
  border: "none",
  outline: "none",
  cursor: "pointer"
}


const container = document.getElementById('root');

ReactDOM.render(<Button btnContent ="按钮A" style = { btnStyle } />, container);

利用setState更改props.gif

О привязке прослушивателя событий this в React

Указание this обычно связано с контекстом его выполнения, как правило, следующим образом:

  • Способ вызова функции влияет на значение this.Если она вызывается как функция, в нестрогом режиме это указывает на глобальный объект окна, а в строгом режиме (используйте «strict») это указывает на undefined

  • Если этот метод называется, это точки для объекта, называемого, который называет его, это точек на то, кто

  • Как вызов функции конструктора, это указывает на исходный объект создания (это указывает на сам этот экземпляр)

  • Вызывается вызовом, применяется, это указывает на первый параметр вызова и применения

В React при привязке события к элементу JSX вам нужно привязать это вручную.Если вы не привязываете вручную, это будет неопределенным.В Es6 компоненты React, созданные с помощью классов классов, не привязывают это автоматически к текущему объекту экземпляра.

Привязка метода экземпляра компонента к этой среде является распространенным методом React.

Код выглядит следующим образом:

import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';

// 类组件
class Button extends Component {
  constructor(props){
  super(props);

  // this坏境的绑定,这是React里面的一个优化,constructor函数只执行一次
  this.handleBtnClick = this.handleBtnClick.bind(this);

  this.state = {
    btnContent: this.props.btnContent
  }

}



render() {
   const { width, height, background, color, border, outline,cursor} = this.props.style;
   const btnStyles = {
       width,
       height,
       background,
       color,
       border,
       outline,
       cursor
}
return (
  <div>
    <button onClick = { this.handleBtnClick } style = { btnStyles }>{ this.state.btnContent }</button>
  </div>
);
}

handleBtnClick(){
  // this.props.btnContent = "按钮B";
  this.setState({
     btnContent: "按钮B"
  });
}
}

const btnStyle = {
  width: "100px",
  height: "40px",
  background: "orange",
  color: "#fff",
  border: "none",
  outline: "none",
  cursor: "pointer"
}


const container = document.getElementById('root');

ReactDOM.render(<Button btnContent ="按钮A" style = { btnStyle } />, container);

Конечно, если эта привязка делает это вручную, функция также возможна со стрелками, стрелка не является функцией этой привязки, следующий код, показанный на фиг.

import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';

// 类组件
class Button extends Component {
   constructor(props){
   super(props);

   // this坏境的绑定,这是React里面的一个优化,constructor函数只执行一次
   // this.handleBtnClick = this.handleBtnClick.bind(this);
   this.state = {
     btnContent: this.props.btnContent
   }

}



render() {
const { width, height, background, color, border, outline,cursor} = this.props.style;
const btnStyles = {
  width,
  height,
  background,
  color,
  border,
  outline,
  cursor
}
return (
  <div>
    <button onClick = { () => { this.handleBtnClick() } } style = { btnStyles }>{ this.state.btnContent }</button>
   <!--或者以下写法-->
   <!--<button onClick = { this.handleBtnClick } style = { btnStyles }>{ this.state.btnContent }</button>-->
  </div>
);
}

handleBtnClick(){
  // this.props.btnContent = "按钮B";
  this.setState({
    btnContent: "按钮B"
  });
}
// handleBtnClick = () => {
// this.setState({
// btnContent: "按钮B"
// });
// }

}



const btnStyle = {
  width: "100px",
  height: "40px",
  background: "orange",
  color: "#fff",
  border: "none",
  outline: "none",
  cursor: "pointer"
}


const container = document.getElementById('root');

ReactDOM.render(<Button btnContent ="按钮A" style = { btnStyle } />, container);

Возможно сравнение двух реализаций, ноОфициальная рекомендация — использовать привязку привязки Использование привязки может не только помочь нам привязать это в методе прослушивателя событий к текущему экземпляру компонента.

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

Со стрелочной функцией этой привязки в стрелочной функции нет.С точки зрения производительности она будет вызываться многократно и выполнять доп.рендеринг.Инициализацию этой среды лучше забиндить вручную в функции-конструкторе.

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

Как показано в следующем коде, окончательный эффект выглядит следующим образом.

子组件向父组件传递内容.gif

import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';

// 定义一个父组件
class ParentComponent extends Component {
  constructor(props){
  super(props);

  console.log("父组件props",props);

}

childContent(parm) {
  alert(parm);
}

render(){
return (
  <Fragment>
     <div>{ this.props.parentContent }</div>
     <ChildComponent getChildContent = { this.childContent } childcon = "我是子组件的内容" ></ChildComponent>
  </Fragment>
);
}
}
// 定义子组件
class ChildComponent extends Component {
  constructor(props){
  super(props);
  console.log("子组件props",props);

}

handleChild = ()=> {
  const {getChildContent, childcon} = this.props;
  getChildContent(childcon);
}

render(){
return (
  <Fragment>
    <div onClick = { this.handleChild }>{ this.props.childcon}</div>
  </Fragment>
);
}
}

const container = document.getElementById('root');

ReactDOM.render(<ParentComponent parentContent = "我是父组件的内容" />, container);

Из приведенного выше кода видно, что значение свойства JSX в родительском компоненте может быть методом,Когда дочерний компонент хочет передать данные родительскому компоненту, ему необходимо вызвать метод родительского компонента в дочернем компоненте, чтобы добиться формы передачи данных от дочернего компонента к родительскому компоненту.

Этот способ косвенности очень важен в React.Конечно, вы видите, что дочерний компонент и родительский компонент размещены в одном файле, что может быть не очень удобно видеть, выПодкомпоненты можно извлекать отдельно.Есть возможность экспортировать и импортировать через экспорт и импорт в Es6 (этот метод часто используется позже)

Создайте файл ChildComponent.js в том же каталоге, что и index.js.

import React, { Component, Fragment} from 'react';

class ChildComponent extends Component {
  constructor(props){
  super(props);
  console.log("子组件props",props);

}

handleChild = ()=> {
  const {getChildContent, childcon} = this.props;
  getChildContent(childcon);
}

render(){
return (
  <Fragment>
   <div onClick = { this.handleChild }>{ this.props.childcon}</div>
  </Fragment>
);
}
}

export default ChildComponent;

В index.js компонент ChildComponent импортируется посредством импорта, как показано в следующем коде.

import React, { Fragment, Component } from 'react';
import ReactDOM from 'react-dom';
import ChildComponent from './ChildComponent'; // 引入ChildComponent组件


// 定义一个父组件
class ParentComponent extends Component {
  constructor(props){
  super(props);

  console.log("父组件props",props);

}

childContent(parm) {
  alert(parm);
}

render(){
return (
  <Fragment>
   <div>{ this.props.parentContent }</div>
     <ChildComponent getChildContent = { this.childContent } childcon = "我是子组件的内容" ></ChildComponent>
  </Fragment>
);
}
}
const container = document.getElementById('root');

ReactDOM.render(<ParentComponent parentContent = "我是父组件的内容" />, container);

Проверка типов с помощью PropTypes

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

Поймайте некоторые ошибки с помощью проверки типов и избегайте некоторых программных ошибок.В React есть несколько встроенных функций проверки типов.Чтобы выполнить проверку типов реквизитов компонента, вам нужно всего лишь настроить некоторые определенные свойства propTypes.

Определяет компонент.Для строгости программы должны быть указаны следующие аспекты данных компонента.

  • Какие реквизиты поддерживает этот компонент

  • Каждый опор должен быть, какой формат

В React для решения этой проблемы используется сторонняя библиотека prop-types, и эта функция поддерживается PropTypes.

В терминале командной строки установите библиотеку prop-types.

cnpm install --save prop-types

В компоненте, который вы хотите проверить, импортируйте библиотеку prop-types.

import PropTypes from 'prop-types'

class PropTest extends Component {

render(){
return (
  <Fragment>
   <div>{ this.props.propContent }</div>
  </Fragment>
);
}
}
// 类组件.propTypes对象下进行配置
PropTest.propTypes = {
   propContent: PropTypes.number
}

const container = document.getElementById('root');

ReactDOM.render(<PropTest propContent = "我是prop属性内容" />, container);

Ошибка консоли показывает следующее:

prop类型的校验.png
Сообщение об ошибке: proppropContent строки типа был предоставлен PropTest, но ожидалось число

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

PropType provides a series of verification methods that ensure that the data type received by the component is effective and accurate. Once the incoming PROP value type is incorrect, the console will display the warning, although the program will not report error, but will A warning появляется.

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

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

Конкретное письмо:

组件.defaultProps = {
 prop属性名称: 默认值
}
import React, { Fragment, Component } from "react";
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';

class PropTest extends Component {

render(){
return (
  <Fragment>
   <div>{ this.props.propContent }</div>
  </Fragment>
);
}
}

PropTest.defaultProps = {
propContent: "我是propTest组件的内容"
}

const container = document.getElementById('root');
ReactDOM.render(<PropTest />, container);

Эффект следующий

设置defaultProps.png
Как и в приведенном выше коде, когда внешний компонент не передает значение propContent, React устанавливает начальное значение по умолчанию через defaultProps.

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

Больше способов в соответствии с определенным пропортом, может обратиться к официальному руководству сайтаИспользование библиотеки PropTypes, вы также можете просмотреть использование библиотеки prop-types в npm

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

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

Компромисс состоит в том, чтобы определить propTypes в коде во время разработки, чтобы избежать ошибок при разработке, но при выпуске кода продукта удалить propTypes автоматически, так что лучший код онлайн-среды будет

с помощьюbabel-plugin-transform-react-remove-prop-typesСторонние модули настроены на его обработку, конкретные детали конфигурации: npm видны на официальном сайте библиотеки:woohoo. эта лошадь plus.com/package/daddy…

Суммировать

В этой статье в основном описываются атрибуты данных — реквизиты в компонентах React, которые аналогичны атрибутам тегов HTML, но значение атрибута может быть любым типом данных, числом, строкой или даже функцией, объектом.

И обратите внимание на разницу в способе написания реквизита в подкомпоненте, когда используется компонент функционального объявления (без сохранения состояния) и компонент объявления класса в Es6.При объявлении компонента с классом класса определите свою собственную функцию-конструктор, обязательно использовать функцию конструктора конструктора и установить для получения параметров реквизита и вызвать супер (реквизит), если этот параметр не установлен, частные методы (функции)-члены, определенные в компоненте, не смогут получить доступ к значению реквизита, переданному родительский компонент через this.props

Конечно, в React оговорено, что значение prop, переданное из внешнего мира, нельзя изменить напрямую, это свойство prop имеет только возможность чтения, конкретные причины можно увидеть выше.

Если вам нужно изменить его, вы можете использовать метод setState, предоставленный React, для внесения изменений.

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

И когда вы знаете, как определить данные реквизита в компоненте, также необходимо проверить тип данных реквизита, передаваемый из внешнего компонента во внутренний компонент, который решается библиотекой типов реквизита.Атрибут экземпляра PropTypes равен используется для установки спецификации реквизита, поэтому при запуске кода вы можете судить, используют ли внешние компоненты свойства компонентов в полном объеме в соответствии с propTypes, и соответствуют ли типы ввода и вывода друг другу и сохраняют ли они то же самое .

Из-за нехватки места: другое состояние данных в React будет изучено в следующей главе.