有条件地从 parent 禁用 child 的按钮 - React

Disable child's button from parent conditionally - React

我有一个 Paginator child 组件,如果它在第一页上,我想禁用左箭头按钮,如果我在第一页上方,我想再次使其可点击。与右箭头按钮相同,但页码为 5。

这是我尝试为此解决方案编写的条件:

if (this.state.page <= 1) {
  this.setState({
    disabledPrev: true
  })
} else {
  this.setState({
    disabledPrev: false
  })
}

if (this.state.page >= 5) {
  this.setState({
    disabledNext: true
  })
} else {
  this.setState({
    disabledNext: false
  })
}

但是无论我把它放在哪里,它都不起作用。我认为问题出在生命周期方法的错误使用上。

完整代码如下:

App.js

import React from 'react';
import './App.css';

import Loading from './components/Loading/Loading';
import Header from './components/Header/Header';
import Table from './components/Table/Table';
import Paginator from './components/Paginator/Paginator';

const BASE_URL = 'https://api.udilia.com/coins/v1/'
export default class App extends React.Component{ 
  constructor(props) {
    super(props);
    console.log('constructor');
    this.state = {
      currencies: null,
      isDataReady: false,
      page : 1,
      disabledPrev: false,
      disabledNext: false,
    }
  }

  fetchCurrencies = (pageNumber) => {
    fetch(`${BASE_URL}cryptocurrencies?page=${pageNumber}&perPage=20`)
      .then(res => res.json())
      .then(json => json.currencies)
      .then(currencies => {
        this.setState({
          currencies: currencies,
          isDataReady: true,
        })
      });
  }

  UNSAFE_componentWillMount() {
    console.log('will mount', this.state.page);

  }

  componentDidUpdate() {
    console.log('didUpdate', this.state.page);

  }

  componentDidMount() {
    console.log('did mount', this.state.page);

    //Here is the conditions
    if (this.state.page <= 1) {
      this.setState({
        disabledPrev: true
      })
    } else {
      this.setState({
        disabledPrev: false
      })
    }

    if (this.state.page >= 5) {
      this.setState({
        disabledNext: true
      })
    } else {
      this.setState({
        disabledNext: false
      })
    }

    const {page} = this.state;

    this.fetchCurrencies(page);

  }

  //here is the event handler, I change the page value from here
  handlePaginationClick  = (direction) => () => {
    console.log('clicked', this.state.page);

    let page = direction === 'next' ? this.state.page + 1 : this.state.page - 1;

    this.setState({page})
    this.fetchCurrencies(page);
  }

  render(){
    console.log('render', this.state.page);

    return (
        !this.state.isDataReady
          ? <Loading />
          : <div className="App">
              <Header />
              <Table
                data={this.state.currencies}
              />
              <Paginator 
                prev={this.handlePaginationClick('prev')}
                next={this.handlePaginationClick('next')}
                page={this.state.page}
                disabledPrev={this.state.disabledPrev}
                disabledNext={this.state.disabledNext}
              />

            </div>
    );
  }
}

Paginator.js

import React from 'react';

export default function Paginator(props) {
    return(
        <div>
            <button disabled={props.disabledPrev} onClick={() => props.prev()}> &larr; </button>
            <span>page {props.page} of 10</span>
            <button disabled={props.disabledNext} onClick={() => props.next()}> &rarr; </button>
        </div>
    )
}
        <Paginator 
            prev={this.handlePaginationClick('prev')}
            next={this.handlePaginationClick('next')}
            page={this.state.page}
            disabledPrev={this.state.page <= 0}
            disabledNext={this.state.page >= 5}
          /> 

componentDidmount 上不需要以下 statements/Condition:

if (this.state.page <= 1) {
  this.setState({
    disabledPrev: true
  })
} else {
  this.setState({
    disabledPrev: false
  })
}

if (this.state.page >= 5) {
  this.setState({
    disabledNext: true
  })
} else {
  this.setState({
    disabledNext: false
  })
}

您不需要两个状态变量来处理左右箭头。
将 Paginator 组件修改为如下所示:

import React from "react";

export default function Paginator({ page, min = 1, max = 5 }) {
  return (
    <div>
      <button disabled={page <= min} onClick={() => props.prev()}>
        &larr;
      </button>
      <span>page {props.page} of 10</span>
      <button disabled={page >= max} onClick={() => props.next()}>
        &rarr;
      </button>
    </div>
  );
} 

minmax 值传递给它。

<Paginator
  prev={this.handlePaginationClick("prev")}
  next={this.handlePaginationClick("next")}
  page={this.state.page}
  min={1}
  max={5}
/>

试试这个

import React from 'react';
import './App.css';

import Loading from './components/Loading/Loading';
import Header from './components/Header/Header';
import Table from './components/Table/Table';
import Paginator from './components/Paginator/Paginator';

const BASE_URL = 'https://api.udilia.com/coins/v1/'
export default class App extends React.Component{ 
  constructor(props) {
    super(props);
    console.log('constructor');
    this.state = {
      currencies: null,
      isDataReady: false,
      page : 1
    }
  }

  fetchCurrencies = (pageNumber) => {
    fetch(`${BASE_URL}cryptocurrencies?page=${pageNumber}&perPage=20`)
      .then(res => res.json())
      .then(json => json.currencies)
      .then(currencies => {
        this.setState({
          currencies: currencies,
          isDataReady: true,
        })
      });
  }

  UNSAFE_componentWillMount() {
    console.log('will mount', this.state.page);

  }

  componentDidUpdate() {
    console.log('didUpdate', this.state.page);

  }

  componentDidMount() {
    console.log('did mount', this.state.page);
    const {page} = this.state;
    this.fetchCurrencies(page);

  }

  //here is the event handler, I change the page value from here
  handlePaginationClick  = (direction) => () => {
    console.log('clicked', this.state.page);

    let page = direction === 'next' ? this.state.page + 1 : this.state.page - 1;

    this.setState({page})
    this.fetchCurrencies(page);
  }

  render(){
    console.log('render', this.state.page);
    const {page} = this.state;
    const disabledPrev = page <=1 ? true : false;
    const disabledNext = page >=5 ? true : false;
    return (
        !this.state.isDataReady
          ? <Loading />
          : <div className="App">
              <Header />
              <Table
                data={this.state.currencies}
              />
              <Paginator 
                prev={this.handlePaginationClick('prev')}
                next={this.handlePaginationClick('next')}
                page={page}
                disabledPrev={disabledPrev}
                disabledNext={disabledNext}
              />

            </div>
    );
  }
}