首页 > 解决方案 > 如何在 ReactJS 中执行下拉状态的突变?

问题描述

我想在我的下拉列表中选择一个项目时更改状态,但是如果不再次单击就不会更改的错误发生。

我知道有相关的问题,但我的代码是一个特例。

示例图像

与我的两个下拉列表中的这张图片相同的事情发生在我身上。

示例图像

我更改了“Mes”,但在您返回并选择另一个值之前它不起作用。在那里,我刚刚更改为“第 4 个月”。

示例图像

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import format from 'date-fns/format';
import gql from 'graphql-tag';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

import { Link } from 'react-router-dom';

import { graphql } from 'react-apollo';

import '../../../node_modules/bootstrap/dist/css/bootstrap.css';
import './style.css';

import {
  ButtonDropdown,
  DropdownToggle,
  DropdownMenu,
  DropdownItem,
} from 'reactstrap';
import axios from 'axios';
import TituloSmall, { types } from '../TituloSmall';

const query0 = gql`
  query postsDiaComoHoy($dia: Int!, $mes: Int!) {
    posts(first: 2, dia: $dia, mes: $mes, categoria: 28) {
      rows {
        id
        fecha_dia_hoy
        imagen_intro
        titulo
        introtext
        autor
        fulltext
        fulltext2
        imagen_banner
        categoria {
          id
        }
        tags {
          id
          titulo
        }
      }
      count
    }
  }
`;

const renderTagItem = item => {
  const { id, titulo } = item;
  return (
    <Link key={id} to={`/tags/${id}/`}>
      <div className="tag">{titulo}</div>
    </Link>
  );
};

const removeTagHtml = valor => valor.replace(/(<([^>]+)>)/g, '');
const removerTwitter = valor => valor.replace(/- @\w+/g, '');

let updated = 0;

let dates = format(Date(), 'D');
let month = format(Date(), 'M');
export class DayScreen extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: this.props,
      currentIndex: 0,
      sortItem1: month,
      sortItem2: dates,
      cantidadMeses: [
        'Enero',
        'Febrero',
        'Marzo',
        'Abril',
        'Mayo',
        'Junio',
        'Julio',
        'Agosto',
        'Septiembre',
        'Octubre',
        'Noviembre',
        'Diciembre',
      ],
      diasMes: [
        1,
        2,
        3,
        4,
        5,
        6,
        7,
        8,
        9,
        10,
        11,
        12,
        13,
        14,
        15,
        16,
        17,
        18,
        19,
        20,
        21,
        22,
        23,
        24,
        25,
        26,
        27,
        28,
        29,
        30,
        31,
      ],
    };
  }

  state = {
    items: [],
  };

  componentDidUpdate() {
    this.getArticles();
    updated = 0;
  }



  getArticles = async () => {
    const changeArticles = `
    {
      posts(first: 3, dia: ${this.state.sortItem2}, mes: ${month}) {
        rows {
          id
          fecha_dia_hoy
          imagen_intro
          titulo
          introtext
          autor
          views
          fulltext
          fulltext2
          imagen_banner
            categoria {
            id
          }
          tags{
            id
            titulo
          }
          }
        count
      }
    }
    `;

    if (updated) {
      try {
        const response = await axios.get(
          `http://localhost:4000/graphql/?query=${changeArticles}`,
        ) .then(response => {
          this.setState(() => ({
            items: response.data.data.posts.rows,
          }));

          let { data } = this.props;
          const { items } = this.state;

          data.posts.rows = items;

          return response;
        });

        // Log the response so we can look at it in the console

        // Set the data to the state



      } catch (error) {
        // If there's an error, set the error to the state
        // this.setState(() => ({ error }));
        console.log(error);
        // console.log(this.state.error);
      }
    }
  };

  selectIndex = direction => {
    const { currentIndex } = this.state;
    const {
      data: {
        posts: { count },
      },
    } = this.props;

    let nexIndex = currentIndex + direction;
    nexIndex = nexIndex < 0 ? count - 1 : nexIndex;
    nexIndex = nexIndex >= count ? 0 : nexIndex;
    this.setState({ currentIndex: nexIndex });
  };

  monthSelected() {
    const { sortItem1, sortItem2, dropdownOpen1 } = this.state;
    this.setState({
      dropdownOpen1: !dropdownOpen1, 
    });
    if (dropdownOpen1) {
      month = sortItem1;
      dates = sortItem2;
      updated = 1;
    }
  }

  dateSelected() {
    const { sortItem1, sortItem2, dropdownOpen2 } = this.state;

    this.setState({
      dropdownOpen2: !dropdownOpen2,
    });
    if (dropdownOpen2) {
      month = sortItem1;
      dates = sortItem2;
      updated = 1;
    }
  }


  onDiasChanged=(e)=>{
     this.setState({sortItem2:[...e.currentTarget.innerHTML]});
   }

   onMesChanged=(e)=>{
    this.setState({sortItem1:[...e.currentTarget.innerHTML]});
  }



  render() {
    const { data } = this.props;
    if (data.loading) {
      return <div>Loading...</div>;
    }
    if (data.error) {
      return <div>{data.error.message}</div>;
    }

    if (data.posts.rows.length <= 0) {
      return <div>Nada que mostrar...</div>;
    }
    const {
      data: {
        posts: { rows },
      },
    } = this.props;

    this.items = this.props.data.posts.rows;
    const {
      currentIndex,
      sortItem1,
      cantidadMeses,
      sortItem2,
      dropdownOpen1,
      dropdownOpen2,
      diasMes,
    } = this.state;

    const item = rows[currentIndex] ? rows[currentIndex] : rows[0];

    const html = item.fulltext + item.fulltext2;
    const image = `${process.env.REACT_APP_IMG_BASE}${item.imagen_intro ||
      item.imagen_banner}`;

    data.variables.mes = sortItem1;
    data.variables.dia = sortItem2;
    return (
      <div className="containerDiaComoHoyNoticia">
        <div className="box">
          <span />
          <span />
          <div className="mesTexto">{cantidadMeses[sortItem1 - 1]}</div>
          <div className="diaTexto">{sortItem2}</div>
        </div>
        <div>
          <div className="textoContainer">
            <div className="tituloDiaComoHoyNoticia">
              {'BUSCA QUE OCURRIÓ EL DÍA QUE TU QUIERAS EN EL FÚTBOL'}
            </div>
            <div className="separatorLinea" />
            <div className="listaMesDia">
              <span className="circuloMesDia">1</span>
              <span>Mes</span>
              <ButtonDropdown
                isOpen={dropdownOpen1}
                toggle={() => {
                  this.monthSelected();
                }}>
                <DropdownToggle color="white" caret>
                  {sortItem1}
                </DropdownToggle>
                <DropdownMenu>
                  {cantidadMeses.map((items, i) => (
                    <DropdownItem
                      dropDownValue="Mes"
                      dropDownValue="Mes" onClick={this.onMesChanged}>
                      {i + 1}
                    </DropdownItem>
                  ))}
                </DropdownMenu>
              </ButtonDropdown>
              <span className="circuloMesDia">2</span>
              <span>Dia</span>

              <ButtonDropdown
                isOpen={dropdownOpen2}
                toggle={() => {
                  this.dateSelected();
                }}>
                <DropdownToggle caret>{sortItem2}</DropdownToggle>
                <DropdownMenu>
                  {diasMes.map(i => (
                    <DropdownItem
                      dropDownValue="Mes" onClick={this.onDiasChanged}>
                      {i}
                    </DropdownItem>
                  ))}
                </DropdownMenu>
              </ButtonDropdown>
            </div>
          </div>
        </div>
        {rows.map(itemArticulo => (
          <div className="listaNoticiasContenido">
            <img
              alt={itemArticulo.titulo}
              src={process.env.REACT_APP_IMG_BASE + itemArticulo.imagen_intro}
              className="listaNoticiasImagen"
            />
            <div className="rectanguloIconoPlay" />
            <div className="contenidoArticulo">
              <div className="tituloArticulo"><a href="#" onClick = {this.state.currentIndex = 1}>{itemArticulo.titulo}</a></div>
              <div className="descripcionArticulo">
                {removeTagHtml(itemArticulo.introtext)}
              </div>
              <div className="escritor">
                <div className="nombreAutor">
                  <div>
                    <FontAwesomeIcon icon="user-circle" />
                    <span className="autorArticulo">
                      {removerTwitter(itemArticulo.autor) || 'Sin autor'}
                    </span>
                    <FontAwesomeIcon icon="eye" />
                    <span className="vistasTotalesArticulos">
                      {itemArticulo.views}
                    </span>
                    <FontAwesomeIcon icon="calendar" />
                    <span className="cantidadArticulosEscritos">
                      {itemArticulo.fecha_dia_hoy}
                    </span>
                  </div>
                </div>
              </div>
            </div>
            <div className="separadorArticulos" />
          </div>
        ))}
        <h2 className="tituloDescripcion">{item.titulo}</h2>
        <div className="titlesContainer">
          <TituloSmall
            iconName="user-circle"
            label={item.autor || 'Sin autor'}
          />
          <TituloSmall
            iconName="calendar"
            label={format(item.fecha_dia_hoy, 'DD/MM/YYYY')}
          />
        </div>

        <div className="imageIntro">
          <img className="imageDescription" src={image} alt={item.titulo} />
          <div className="esquinaFigura">
            <div className="boxWhite">
              <span />
              <span />
              <div className="mesTextoBoxWhite">
                {cantidadMeses[sortItem1 - 1]}
              </div>
              <div className="diaTextoBoxWhite">{sortItem2}</div>
            </div>
          </div>
        </div>

        <article dangerouslySetInnerHTML={{ __html: html }} />
        <TituloSmall iconName="tags" label="Tags" type={types.BIG} />
        {item.tags.map(itemsTags => renderTagItem(itemsTags))}
      </div>
    );
  }
}

DayScreen.propTypes = {
  data: PropTypes.shape({
    loading: PropTypes.bool.isRequired,
    currentSortItem: PropTypes.string.isRequired,
    error: PropTypes.shape({ message: PropTypes.string }),
  }).isRequired,
};

DayScreen.defaultProps = {};

const queryOptions = {
  options: () => ({
    variables: {
      dia: dates,
      mes: month,
    },
  }),
};

export default graphql(query0, queryOptions)(DayScreen);

我希望在不按双击的情况下进行状态更改,并且我在图像中显示的延迟会发生。

谢谢你的帮助!

标签: reactjsreact-nativereact-reduxgraphql

解决方案


You have directly mutated the state and not setting the state using setState method so your render method will not be called at the time of selection and because of it, you will not getting the change immediately once your render method will be call you will get those changes. so your dropdown implementation should be like.

  onMessChanged=(e)=>{
     this.setState({sortItem2:e.currentTarget.innerHTML});
    }

  <DropdownMenu>
                  {diasMes.map(i => (
                    <DropdownItem
                      dropDownValue="Mes"
                      onClick={this.onMessChanged}>
                      {i}
                    </DropdownItem>
                  ))}
                </DropdownMenu>

As here you are using the reactstrap so it might be possible that your event target may be different so you have to use currentTarget

the currentTarget refers to the element that the event listener directly attached to while the target still refers to the specific element where we clicked.


推荐阅读