Наверное, новенький вопрос. Я новичок в реакции.
Следуя некоторым сообщениям в блогах и тому подобному, я смог создать страницу, в которой компоненты более высокого порядка и componentDidMount загружали данные из API и отображали их на странице. Он отлично работает, и код выглядит чистым, хотя я не могу понять, как передать какой-то onClick через компонент более высокого порядка, в конечном итоге я бы хотел переместить внутренности выборки в функцию, которая может быть вызвана как componentDidMount, так и <Button onClick = {}>Reload</Button>. Halp, пожалуйста
import React, { Component } from 'react';
import {Button, CardColumns, Card, CardHeader, CardBody} from 'reactstrap';
const API = 'http://localhost:3000/';
const DEFAULT_QUERY = 'endpoint';
const withFetching = (url) => (Comp) =>
class WithFetching extends Component {
constructor(props) {
super(props);
this.state = {
data: {},
isLoading: false,
error: null,
};
// Goes here?
this.onClick = () => {
console.info("Handled!");
};
}
componentDidMount() {
this.setState({ isLoading: true });
fetch(url)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong ...');
}
})
.then(data => this.setState({ data, isLoading: false }))
.catch(error => this.setState({ error, isLoading: false }));
}
// Or here maybe??
this.onClick = () => {
console.info("Handled!");
};
render() {
// How do I pass it in?
return <Comp { ...this.props } { ...this.state } onClick = {this.onClick} />
}
}
// How do I tell this component to expect it to recieve the handler?
const App = ({ data, isLoading, error }) => {
const hits = data.hits || [];
console.info(data);
if (error) {
return <p>{error.message}</p>;
}
if (isLoading) {
return <p>Loading ...</p>;
}
return (
<div className = "animated fadeIn">
<CardColumns className = "cols-2">
<Card>
<CardHeader>
API Card!
<div className = "card-actions">
</div>
</CardHeader>
<CardBody>
{hits.map(hit =>
<div key = {hit.foo}>
<h3>{hit.foo}</h3>
_____
</div>
)}
<Button onClick = {props.onClick}>Launch demo modal</Button>
</CardBody>
</Card>
</CardColumns>
</div>
);
}
export default withFetching(API + DEFAULT_QUERY)(App);
Здесь - это сообщение в блоге, которое привело меня к архитектуре, которую я использую:
Обновлено: я могу создать функцию вне класса, чтобы она была доступна везде, но причина, по которой я изначально хотел оставить ее в, заключалась в том, чтобы я мог фактически изменить состояние и повторно отобразить карту с новыми данными. Пытаюсь понять, как правильно использовать bind() для этой работы ... JS иногда заставляет меня чувствовать себя глупо: p
Каков правильный синтаксис, чтобы это работало?
@ mohhamad-hasham - это кажется правильным ответом, но я не могу понять его правильно. Какие-нибудь советы?
Можете ли вы сказать, что кажется неправильным? так что я могу вам помочь!



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


Вы думали о том, чтобы сделать эту функцию функцией корневого уровня вне всех классов? Тогда любой компонент может его вызвать.
Например:
import React, { Component } from 'react';
import {Button, CardColumns, Card, CardHeader, CardBody} from 'reactstrap';
const API = 'http://localhost:3000/';
const DEFAULT_QUERY = 'endpoint';
function sharedUtilityFunction(){
// Do something here
}
const withFetching = (url) => (Comp) =>
class WithFetching extends Component {
constructor(props) {
super(props);
this.state = {
data: {},
isLoading: false,
error: null,
};
}
componentDidMount() {
sharedUtilityFunction();
this.setState({ isLoading: true });
fetch(url)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong ...');
}
})
.then(data => this.setState({ data, isLoading: false }))
.catch(error => this.setState({ error, isLoading: false }));
}
render() {
return <Comp { ...this.props } { ...this.state } />
}
}
// How do I tell this component to expect it to recieve the handler?
const App = ({ data, isLoading, error }) => {
const hits = data.hits || [];
console.info(data);
if (error) {
return <p>{error.message}</p>;
}
if (isLoading) {
return <p>Loading ...</p>;
}
return (
<div className = "animated fadeIn">
<CardColumns className = "cols-2">
<Card>
<CardHeader>
API Card!
<div className = "card-actions">
</div>
</CardHeader>
<CardBody>
{hits.map(hit =>
<div key = {hit.foo}>
<h3>{hit.foo}</h3>
_____
</div>
)}
<Button onClick = {() => sharedUtilityFunction()}>Launch demo modal</Button>
</CardBody>
</Card>
</CardColumns>
</div>
);
}
export default withFetching(API + DEFAULT_QUERY)(App);
Я открыт для этого. Быстрый пример?
@msanteler Переместить функцию за пределы класса. function onClick()....
Огромное спасибо. Похоже, это должно сработать! Это не раскрывает это глобально или что-то в этом роде, верно?
Кроме того, может ли эта корневая функция взаимодействовать с состоянием, чтобы я мог this.setState({ isLoading: true }); и т. д.?
Код с глобальной областью видимости может означать разные вещи в разном контексте. Похоже, вы используете импорт, поэтому обычно я создаю файл "utilities.js" с такими функциями и импортирую их по мере необходимости. Если вы хотите вызвать this.setState, просто передайте функцию this.setState в качестве параметра функции и вызовите ее внутри, или [привязать функцию] (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…)
Ответ, который я искал, действительно передавал функцию компоненту более низкого порядка в качестве опоры. Для этого мне нужно было изменить способ, которым ожидаемые аргументы компонента должны быть: const App = props => { TBD, независимо от того, имеет ли это другое повторение, но я в любом случае состояние считать уже передавало опору ... вызов функции должным образом вызывает рендеринг isLoading, поэтому это хороший знак.
import React, { Component } from 'react';
import {Button, CardColumns, Card, CardHeader, CardBody} from 'reactstrap';
const API = 'http://localhost:3000/';
const DEFAULT_QUERY = 'endpoint';
const withFetching = (url) => (Comp) =>
class WithFetching extends Component {
constructor(props) {
super(props);
this.state = {
data: {},
isLoading: false,
error: null,
};
this.goFetch = this.goFetch.bind(this);
}
goFetch() {
this.setState({ isLoading: true });
fetch(url)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong ...');
}
})
.then(data => this.setState({ data, isLoading: false }))
.catch(error => this.setState({ error, isLoading: false }));
}
componentDidMount() {
this.goFetch();
}
render() {
return <Comp { ...this.props } { ...this.state } goFetch = {this.goFetch}/>
}
}
const App = props => {
const hits = props.data.hits || [];
if (props.error) {
return <p>{props.error.message}</p>;
}
if (props.isLoading) {
return <p>Loading ...</p>;
}
return (
<div className = "animated fadeIn">
<CardColumns className = "cols-2">
<Card>
<CardHeader>
API Card!
<div className = "card-actions">
</div>
</CardHeader>
<CardBody>
{hits.map((hit, index) =>
<div key = {index}>
Foo: <h3>{hit.foo}</h3>
</div>
)}
<Button onClick = {props.goFetch}>Refresh</Button>
</CardBody>
</Card>
</CardColumns>
</div>
);
}
export default withFetching(API + DEFAULT_QUERY)(App);
Этот должен быть правильным. Может быть, один рефакторинг определяет goFetch с помощью толстой стрелки, например goFetch = () => {...}, таким образом, нам не нужно выполнять this.goFetch = tihs.goFetch.bind(this) в конструкторе. Причина Функции жирных стрелок ES6 сохраняют этот контекст при вызове.
вы можете передать функцию onclick как опору