使用高阶组件时绑定 onClick

Bind onClick when using higher order component

可能是个新问题。我是新来的反应。

关注一些博客 post 之类的,我能够构建一个包含高阶组件的页面和 componentDidMount 从 API 加载数据并将其呈现到页面.它工作得很好,代码看起来很干净,但我不知道如何通过高阶组件传递某种 onClick,最终我想将获取的内容移动到一个可以调用的函数中componentDidMount<Button onClick={}>Reload</Button>。请打住

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.log("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.log("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.log(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);

Here 是博客 post 引导我找到我正在使用的架构:

编辑:我可以在 class 之外创建一个函数,以便它在任何地方都可用,但我最初想将它留在 的原因是我实际上可以改变状态并用新数据重新渲染卡片。试图找出 bind() 的正确用法来完成这项工作...... JS 有时让我觉得很愚蠢 :p

您是否考虑过将该函数设为所有 类 之外的根级函数?然后任何组件都可以调用它。

例如:

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.log(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);

我一直在寻找的答案确实是将函数作为 prop 传递给低阶组件。为此,我需要将 compent 预期参数的方式更改为:const App = props => { 待定,无论这是否有其他影响,但我 认为 状态已经通过了prop 无论如何......正确调用函数会导致 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);