【问题标题】:Show/hide button based on state React基于状态 React 显示/隐藏按钮
【发布时间】:2022-01-26 02:54:42
【问题描述】:

我有一个叫做下载的按钮,它是一个组件。功能写在一个容器中。

我希望按钮默认隐藏,除非下载函数中的“(i === number)”条件为真。

但是,这很棘手,因为只有在我单击“下载”时才会验证此条件。我不确定如何事先验证此逻辑以确定是否需要显示按钮。

你能帮忙吗?我正在尝试设置显示按钮的状态,但它不起作用。

我的代码基本上是这样的 -

容器:

state = {
  showButton: false,
};

componentDidMount() {
  this.download();
};

download = async () => {
  const data = await this.props.client
      .query({
          query: numberQuery,
          fetchPolicy: "no-cache",
      })
  // retrive data from number query ....
  const contentData = data.data.content;
 
  // retrieve and format numbers
  const numbers = this.getNumbers(contentData);
 
  // call get number and get the individual number here
  const number = await this.getNumber();
 
  numbers.forEach((i) => {
     // this is to check if numbers contain the number from getNumber(), if 
     // number matches number in numbers
     if (i === number) {
       this.setState({
        showButton: true,
       });
          // call functions, start downloading
     };
   });
  };
 
 render() {
   return (
     {this.state.showButton ? 
      <Download 
      onStartDownload={() => this.download()}
      /> : null}
    );
 };

组件:

 class Download extends Component {
  state = {
    startDownload: false,
  };
 
  startDownload = () => {
    this.props.onStartDownload();
  };
 
  render() {
    return (
      <Fragment>
        <Button
          id="download"
          onClick={this.startDownload}
        >
          Download
        </Button>
      </Fragment>
     );
    };
  };

【问题讨论】:

    标签: javascript css reactjs components


    【解决方案1】:

    如果我理解正确,您的问题是仅在单击下载按钮后才获取数字(并且运行显示/隐藏按钮的逻辑),但您希望它尽快运行可能(即在组件的挂载上)。

    通常,React 中的数据获取与渲染/事件处理程序逻辑是分开的。在您的情况下,解决方案是在组件安装时获取数据,将其保存在状态(例如numbersnumber 字段),然后在渲染时检查number 是否在numbers数组。

    例如:

    // Container component; child component remains the same
    
    state = {
      number: null,
      numbers: []
    };
    
    componentDidMount() {
      this.fetchNumbers();
      this.fetchNumber();
    };
    
    async fetchNumbers() {
      const data = await this.props.client
      .query({
          query: numberQuery,
          fetchPolicy: 'no-cache',
      });
      // retrive data from number query ....
      const contentData = data.data.content;
    
      // retrieve and format numbers
      const numbers = this.getNumbers(contentData);
    
      this.setState({ numbers });
    }
    
    async fetchNumber() {
      // Assuming this is another HTTP request or something similar
      const number = await this.getNumber();
    
      this.setState({ number });
    }
    
    download = async () => {
      // *only* downloading logic
    };
     
     render() {
        const { number, numbers } = this.state;
        const showDownload = numbers.includes(number);
    
        return showDownload 
            ? <Download onStartDownload={() => this.download()}/> 
            : null;
     };
    }
    

    注意事项:

    • 使用Array.includes() 而不是Array.forEach() 循环可以简化代码(并且将来可能会为您节省一些错误!)
    • 我将获取this.state.numbersfetchNumbers() 与获取this.state.numberfetchNumber() 分开,仅仅是因为它们看起来像是两个独立的状态(因此独立获取它们是最有效的);您可以通过让这两个函数返回数据(而不是更改状态)来进一步改进它,然后在 componentDidMount() 中使用 Promise.all()(为了简单起见,我省略了它)。
    • 通常在 web 开发中,异步获取核心数据的最佳实践是指示组件在数据到达之前不加载(例如,使用加载器)。对于实践或原型,它可能不是您的首要任务,但在生产时请记住这一点。

    【讨论】:

    • 谢谢!您是说,我没有检查 numbers.forEach 是否为(i === number),而是使用包含()。我明白那个。但是,我在下载函数中确实有这段逻辑: const locate = numbers.indexOf(number); // 在 numbers 数组中找到 number 的索引。然后在 if (i === number) 条件下,我有: const content= this.transformArray(contentData[locate]); // 仅转换数组/下载数字数组中该索引的数据如果我将其余部分移至 fetchNumbers(),如何将此逻辑应用于下载函数?由于 contentData 也在那里谢谢你
    • @soso1234 我不确定我是否完全理解您所说的在download() 函数中需要做什么,但您应该能够使用this.state.numbersthis.state.number 而不是@987654337 @ 和number,结果应该几乎相同。至于contentData,如果您需要在download() 或其他任何地方使用它,将其存储在组件的状态中可能会有所帮助(就像您对numbers 所做的那样!)对您有用吗?
    • 谢谢,像这样? - state = { contentData: [], }; async fetchContent() { const data = await this.props.client .query({ query: numberQuery, fetchPolicy: "no-cache", }) // same code const contentData = data.data.content; this.setState({ contentData }); } 无论我在哪里需要这些数据,我都会打电话给this.state.contentData,对吗?我试了一下,控制台日志this.state.contentData,里面好像什么都没有。
    • 这看起来不错。一个建议是,在您的原始代码中,您从contentData 派生了numbers,因此您可以在fetchContent() 中执行相同的操作并保存一个HTTP 请求。至于调试,也许在收到fetchContent() 的响应时尝试记录一条消息?它可能会帮助您查明错误的根源
    • 我试过showdownload总是返回false。
    【解决方案2】:

    你需要在你的类组件中有一个构造函数并更新你需要使用setState()的状态, 查看要遵循的代码 :

     class Download extends react.Component {
      constructor() {
        super();// required
        this.state = {
          startDownload: false
        };
      }
    
      startDownload = () => {
        this.setState((prevState) => ({
          // I use prevState, to bring the previous state value
          startDownload: !prevState.startDownload // here the value is inverted
        }));
      };
    
      render() {
        return (
          <> // this is equivalent to the fragment
            <button id="download" onClick={this.startDownload}>
              Download
            </button>
          </>
        );
      }
    }
    

    【讨论】:

    • 为什么这段代码的行为与 OP 当前的代码有任何不同?状态被定义为一个类字段,它不需要显式地在 constructor()
    猜你喜欢
    • 2018-03-29
    • 1970-01-01
    • 2012-09-18
    • 2019-03-19
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    • 2018-11-27
    • 2021-11-01
    相关资源
    最近更新 更多