Свяжите onClick при использовании компонента более высокого порядка

Наверное, новенький вопрос. Я новичок в реакции.

Следуя некоторым сообщениям в блогах и тому подобному, я смог создать страницу, в которой компоненты более высокого порядка и 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

вы можете передать функцию onclick как опору

Mohhamad Hasham 20.04.2018 23:29

Каков правильный синтаксис, чтобы это работало?

msanteler 22.04.2018 16:42

@ mohhamad-hasham - это кажется правильным ответом, но я не могу понять его правильно. Какие-нибудь советы?

msanteler 23.04.2018 15:18

Можете ли вы сказать, что кажется неправильным? так что я могу вам помочь!

Mohhamad Hasham 23.04.2018 21:59
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
4
1 083
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Например:

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 20.04.2018 23:25

@msanteler Переместить функцию за пределы класса. function onClick()....

Phix 20.04.2018 23:26

Огромное спасибо. Похоже, это должно сработать! Это не раскрывает это глобально или что-то в этом роде, верно?

msanteler 20.04.2018 23:31

Кроме того, может ли эта корневая функция взаимодействовать с состоянием, чтобы я мог this.setState({ isLoading: true }); и т. д.?

msanteler 20.04.2018 23:32

Код с глобальной областью видимости может означать разные вещи в разном контексте. Похоже, вы используете импорт, поэтому обычно я создаю файл "utilities.js" с такими функциями и импортирую их по мере необходимости. Если вы хотите вызвать this.setState, просто передайте функцию this.setState в качестве параметра функции и вызовите ее внутри, или [привязать функцию] (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…)

Wyatt Arent 20.04.2018 23:35
Ответ принят как подходящий

Ответ, который я искал, действительно передавал функцию компоненту более низкого порядка в качестве опоры. Для этого мне нужно было изменить способ, которым ожидаемые аргументы компонента должны быть: 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 сохраняют этот контекст при вызове.

Kevin Li 23.04.2018 18:03

Другие вопросы по теме