В этом примере у меня есть класс реакции:
class MyDiv extends React.component
constructor(){
this.state = {sampleState:'hello world'}
}
render(){
return <div>{this.state.sampleState}
}
}
Вопрос в том, могу ли я добавить к этому хуки React. Я понимаю, что React-Hooks - альтернатива стилю React Class. Но если я хочу постепенно перейти на хуки React, могу ли я добавить полезные хуки в классы?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Компоненты класса не поддерживают хуки -
Согласно Хуки-FAQ:
You can’t use Hooks inside of a class component, but you can definitely mix classes and function components with Hooks in a single tree. Whether a component is a class or a function that uses Hooks is an implementation detail of that component. In the longer term, we expect Hooks to be the primary way people write React components.
Я все время вижу React.createRef внутри классов и путаюсь, думая, что это React.useRef ?
Это будет невозможно с вашими существующими компонентами класса. Вам нужно будет преобразовать свой компонент класса в функциональный компонент, а затем сделать что-то в строках -
function MyDiv() {
const [sampleState, setSampleState] = useState('hello world');
return (
<div>{sampleState}</div>
)
}
Хуки предназначены не для классов, а для функций. Если вы хотите использовать хуки, вы можете начать с написания нового кода в виде функциональных компонентов с хуками.
Согласно Ответы на часто задаваемые вопросы
You can’t use Hooks inside of a class component, but you can definitely mix classes and function components with Hooks in a single tree. Whether a component is a class or a function that uses Hooks is an implementation detail of that component. In the longer term, we expect Hooks to be the primary way people write React components.
const MyDiv = () => {
const [sampleState, setState] = useState('hello world');
render(){
return <div>{sampleState}</div>
}
}
его должно быть setSampleState нет?
Это простая деструктуризация массива и может называться как угодно. setState, setSampleState, setABC
Как уже объясняется в других ответах, API-интерфейс хуков был разработан для предоставления функциональным компонентам функциональности, которая в настоящее время доступна только в компонентах класса. Хуки не должны использоваться в компонентах класса.
Компоненты класса могут быть написаны для облегчения перехода к функциональным компонентам.
С одним состоянием:
class MyDiv extends Component {
state = {sampleState: 'hello world'};
render(){
const { state } = this;
const setState = state => this.setState(state);
return <div onClick = {() => setState({sampleState: 1})}>{state.sampleState}</div>;
}
}
конвертируется в
const MyDiv = () => {
const [state, setState] = useState({sampleState: 'hello world'});
return <div onClick = {() => setState({sampleState: 1})}>{state.sampleState}</div>;
}
Обратите внимание, что средство установки состояния useState не объединяет свойства состояния автоматически, это должно быть покрыто setState(prevState => ({ ...prevState, foo: 1 }));
С несколькими состояниями:
class MyDiv extends Component {
state = {sampleState: 'hello world'};
render(){
const { sampleState } = this.state;
const setSampleState = sampleState => this.setState({ sampleState });
return <div onClick = {() => setSampleState(1)}>{sampleState}</div>;
}
}
конвертируется в
const MyDiv = () => {
const [sampleState, setSampleState] = useState('hello world');
return <div onClick = {() => setSampleState(1)}>{sampleState}</div>;
}
Компоненты высокого порядка - вот как мы делали подобные вещи, пока не появились хуки. Вы можете написать простую оболочку компонента высокого порядка для вашего хука.
function withMyHook(Component) {
return function WrappedComponent(props) {
const myHookValue = useMyHook();
return <Component {...props} myHookValue = {myHookValue} />;
}
}
Хотя на самом деле это не совсем использование ловушки непосредственно из компонента класса, это, по крайней мере, позволит вам использовать логика вашей ловушки из компонента класса без рефакторинга.
class MyComponent extends React.Component {
render(){
const myHookValue = this.props.myHookValue;
return <div>{myHookValue}</div>;
}
}
export default withMyHook(MyComponent);
Отличный ответ. Я использовал этот подход для пакета response-alert, который был написан с помощью хуков.
Можно ли присвоить значение непосредственно классу (MyDiv)? Выдает ошибку es-lint!
@TusharShukla Технически нормально перезаписывать такое значение класса, но в целом это немного осуждается, и да, eslint хочет остановить это по умолчанию. Обновленный пример, чтобы было понятнее.
Разве в первом блоке кода в строке возврата не должно быть Component вместо MyComponent?
@NicholasHamilton Нет - пример правильный. Первый блок кода является примером оболочки компонента высокого порядка для компонента класса во втором блоке кода. В этом примере оболочка компонента высокого порядка использует ловушку useMyHook() и предоставляет результат этой ловушки в качестве опоры с именем myHookValue компоненту класса.
@JoelCox Подпись первой функции - function withMyHook(Component) {...}, а Component не передается в оператор возврата. Его может даже не быть, и, конечно, это будет работать, только если функция withMyHook(...) также определена в той же области, что и определение класса MyComponent.
Я бы сказал, что функции должны быть: function withMyHook(Component) { return function WrappedComponent(props) { const myHookValue = useMyHook(); return <Component {...props} myHookValue = {myHookValue} />; } }
Ах! да - извините, вы правы @NicholasHamilton, эта часть была опечаткой ? хорошая уловка, и извините, что я неправильно понял в вашем последнем комментарии.
Привет, @JoelCox, это круто. Можно ли заставить компоненты класса отправлять состояние хукам? Если взять пример из официального документа React, если у нас есть перехватчик useIsFriendOnline (friendId), могут ли компоненты класса использовать этот вид перехватчика?
Добавил вопрос по той же проблеме stackoverflow.com/questions/68782054/…
Компоненты с сохранением состояния, контейнеры или компоненты на основе классов когда-либо поддерживают функции React Hooks, поэтому нам не нужно React Hooks в компонентах с отслеживанием состояния только в компонентах без состояния.
Некоторая дополнительная информация
Что такое перехватчики React? Так что же такое хуки? Хуки - это новый способ или новый способ написания наших компонентов.
До сих пор, конечно, у нас есть функциональные и классовые компоненты, не так ли? Функциональные компоненты получают реквизиты, а вы возвращаете некоторый JSX-код, который должен отображаться на экране.
Они отлично подходят для презентации, поэтому для визуализации части пользовательского интерфейса, не столько о бизнес-логике, и они обычно ориентированы на одну или несколько целей для каждого компонента.
С другой стороны, компоненты на основе классов также получат реквизиты, но у них также есть это внутреннее состояние. Поэтому компоненты на основе классов - это компоненты, которые на самом деле содержат большую часть нашей бизнес-логики, поэтому под бизнес-логикой я имею в виду такие вещи, как мы делаем HTTP-запрос, и нам нужно обработать ответ и изменить внутреннее состояние приложения или, возможно, даже без HTTP. Пользователь заполняет форму, и мы хотим показать это где-нибудь на экране, нам нужно состояние для этого, нам нужны компоненты на основе классов для этого, и поэтому мы также обычно используем компоненты на основе классов для координации наших других компонентов и передачи нашего состояния вниз. например, в качестве опоры для функциональных компонентов.
Теперь у нас есть одна проблема с этим разделением со всеми преимуществами, которые оно добавляет, но одна проблема, которая у нас есть, заключается в том, что преобразование из одной формы компонента в другую раздражает. Это не очень сложно, но раздражает.
Если вы когда-нибудь оказывались в ситуации, когда вам нужно было преобразовать функциональный компонент в компонент на основе классов, вам придется много печатать и много печатать всегда одни и те же вещи, поэтому это раздражает.
Более серьезная проблема в кавычках состоит в том, что хуки жизненного цикла сложно использовать правильно.
Очевидно, нетрудно добавить componentDidMount и выполнить там некоторый код, но зная, какой крючок жизненного цикла использовать, когда и как его правильно использовать, это может быть сложно, особенно в более сложных приложениях, и в любом случае, было бы неплохо, если бы мы был один способ создания компонентов, и этот суперкомпонент мог затем обрабатывать как состояние, так и побочные эффекты, такие как HTTP-запросы, а также отображать пользовательский интерфейс?
Что ж, в этом и суть крючков. Хуки дают нам новый способ создания функциональных компонентов, и это важно.
Написание компонентов класса не проблема. Их можно быстро написать и отремонтировать. Настоящая цель хуков не в том, чтобы облегчить набор текста, а в том, чтобы упростить обмен логикой между различными компонентами. Еще одно замечание: если вы не знаете, какой метод жизненного цикла использовать, то вы также застрелитесь с помощью крючков.
React Hooks позволяет использовать функции и жизненный цикл реакции без написания класса. Это похоже на эквивалентную версию компонента класса с гораздо меньшим и удобочитаемым форм-фактором. Вам следует перейти на хуки React, потому что писать их весело. Но вы не можете писать перехватчики реакции внутри компонента класса, как это было введено для функционального компонента.
Это можно легко преобразовать в:
class MyDiv extends React.component
constructor(){
this.state = {sampleState:'hello world'}
}
render(){
return <div>{this.state.sampleState}
}
}
const MyDiv = () => {
const [sampleState, setSampleState] = useState('hello world');
return <div>{sampleState}</div>
}
Для меня React.createRef () был полезен.
бывший.:
constructor(props) {
super(props);
this.myRef = React.createRef();
}
...
<FunctionComponent ref = {this.myRef} />
Сообщение происхождения здесь.
Вы можете использовать библиотеку универсальные хуки. Он позволяет вам использовать функции «useXXX» в функции рендеринга компонентов класса.
До сих пор у меня это работало отлично. Единственная проблема заключается в том, что, поскольку он не использует официальные хуки, значения не показывают react-devtools.
Чтобы обойти это, я создал эквивалент, обернув хуки и заставив их хранить свои данные (используя мутацию объекта для предотвращения повторного рендеринга) на component.state.hookValues. (вы можете получить доступ к компоненту, автоматически обернув функции компонента render, чтобы запустить набор currentCompBeingRendered = this)
Дополнительные сведения об этой проблеме (и подробные сведения об обходном пути) см. Здесь: https://github.com/salvoravida/react-universal-hooks/issues/7
Дополняя Хороший ответ Джоэла Кокса
Рендеринг реквизита также позволяет использовать хуки внутри компонентов класса, если требуется большая гибкость:
class MyDiv extends React.Component {
render() {
return (
<HookWrapper
// pass state/props from inside of MyDiv to Hook
someProp = {42}
// process Hook return value
render = {hookValue => <div>Hello World! {hookValue}</div>}
/>
);
}
}
function HookWrapper({ someProp, render }) {
const hookValue = useCustomHook(someProp);
return render(hookValue);
}
Для хуков побочного эффекта без возвращаемого значения:
function HookWrapper({ someProp }) {
useCustomHook(someProp);
return null;
}
// ... usage
<HookWrapper someProp = {42} />
Источник: React Обучение
да, но не напрямую.
Попробуйте react-iifc, подробности в readme.
import withComponentHooks from 'with-component-hooks';
class MyComponent extends React.Component {
render(){
const props = this.props;
const [counter, set] = React.useState(0);
//TODO...
}
}
export default withComponentHooks(MyComponent)
2. попробуйте response-iifc : https://github.com/EnixCoda/react-iifc
вы можете добиться этого с помощью общего Компоненты высокого порядка
import React from 'react';
const withHook = (Component, useHook, hookName = 'hookvalue') => {
return function WrappedComponent(props) {
const hookValue = useHook();
return <Component {...props} {...{[hookName]: hookValue}} />;
};
};
export default withHook;
class MyComponent extends React.Component {
render(){
const myUseHookValue = this.props.myUseHookValue;
return <div>{myUseHookValue}</div>;
}
}
export default withHook(MyComponent, useHook, 'myUseHookValue');
Но давайте помнить, что мы определенно можем смешивать классы и функциональные компоненты в одном дереве.