【问题标题】:React onClick method反应 onClick 方法
【发布时间】:2018-04-08 01:50:58
【问题描述】:

我正在尝试制作一个带有 react 的手风琴应用程序,我有来自 API 的数据,并且我有应用程序的基本轮廓,但我不确定如何处理手风琴上的点击。

这是我的代码:

这是我设置数据的地方

App.js

class App extends Component {
  constructor(){
    super();
    this.state = {
      myData: {}
    };
  }

  componentDidMount() {
    axios.get(linkToApi)
      .then(responseData => {
        this.setState({ mydata: responseData.data });
      })
      .catch(error => {
        console.log("Porblem getting data", error);
      });
  }

  render() {
    return (
      <div className="App">
        <Accordion data={this.state.myData} />
      </div>
    );
  }
}

export default App;

手风琴.js

const Accordion = props => {
   let accordionElements = Object.keys(props.data).map(function(keyName, keyIndex) {
     return <AccordionElement
            {...props.data[keyName]}
            key={props.data[keyName].id}
          />;
 })


return (
   <ul className="accordion">
     {accordionElements}
   </ul>
 );
 }
 export default Accordion;

AccordionElement.js

const AccordionElement = props => {

 const handleOnClick = (e) => {
   e.preventDefault();
   //
 }

 return (
   <li style={listItemStyle} onClick={handleOnClick}>
     <h1 data={props}>{ props.name }</h1>
     <ul style={descriptionStyle}>
       <li>Description: { props.description }</li>
     </ul>
   </li>
 );

}

export default AccordionElement;

我希望能够在单击标题时显示或隐藏其下方的描述。我真的不确定我会怎么做,有什么想法吗?

【问题讨论】:

标签: javascript reactjs accordion


【解决方案1】:

如果描述在给定时间可见,我会使用状态来管理。所以是这样的:

class AccordionElement extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      open: false
    }
  }

  const handleOnClick = (e) => {
    e.preventDefault();
    this.setState({ open: !this.state.open });
  }

  renderDescription() {
    const description = (
      <ul style={descriptionStyle}>
        <li>Description: { props.description }</li>
      </ul>
    );
    return this.state.open ? description : null;
}

  return (
    <li style={listItemStyle} onClick={handleOnClick}>
      <h1 data={props}>{ props.name }</h1>
      {this.renderDescription()} 
    </li>
  );

}

export default AccordionElement;

编辑:我已经解决了一些问题;现在应该可以按预期工作,将AccordionAccordionElement 保留为功能组件。代码如下:

class App extends React.Component {
  constructor(){
    super();
    this.state = {
      myData: []
    };
    this.setOpenStatus = this.setOpenStatus.bind(this);
  }

  componentDidMount() {
    // this would be inside the API call
        const myData = [
        {
        id: 1,
        name: 'Item 1',
        description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut varius metus tellus, eu tincidunt est viverra vitae. Fusce et mollis libero.'
      }, {
        id: 2,
        name: 'Item 2',
        description: 'Ut interdum ut justo ac euismod. Phasellus vitae pellentesque lectus, et cursus erat. Suspendisse eget risus gravida tellus rutrum gravida et vitae felis.'
      }, {
        id: 3,
        name: 'Item 2',
        description: ' Cras euismod massa eu mi consequat mollis. Sed aliquam tellus sed sem dictum feugiat. Nullam pretium purus sed ipsum pharetra luctus.'
      }
    ];
    myData.forEach(item => {
        item.open = false;
    });
    this.setState({ myData });
  }

  setOpenStatus(id) {
    console.log(this.state);
    const myData = this.state.myData;
    myData.forEach(item => {
        if (item.id == id) {
        item.open = !item.open;
      } else {
        item.open = false;
      }
    });
    this.setState({ myData });
  }

  render() {
    return (
      <div className="App">
        <Accordion data={this.state.myData} setOpenStatus={this.setOpenStatus} />
      </div>
    );
  }
}

const Accordion = props => {
   let accordionElements = [];
   const {data} = props;
   if (data && data.length > 0) {
     data.forEach(item => {
       console.log('props', item);
       accordionElements.push(<AccordionElement
              {...item}
              setOpenStatus={props.setOpenStatus}
              key={item.id}
            />);
     });
   }


return (
   <ul className="accordion">
     {accordionElements}
   </ul>
 );
 }

const AccordionElement = props => {

 const handleOnClick = (e) => {
   e.preventDefault();
     props.setOpenStatus(props.id);
 }

 const renderDescription = () => {
    return props.open ? props.description : null;
 }

 return (
   <li onClick={handleOnClick}>
     <h1>{ props.name }</h1>
     <span>{ renderDescription() }</span>
   </li>
 );

}

setOpenStatus(id) 函数作为道具传递给AccordionElement,然后在点击处理程序上调用。这会在myData 状态数组中找到 ID 并切换 open 布尔值,然后将其他 open 布尔值更改为 false,因此只有单击的那个可以为 true。 jsfiddle链接。

【讨论】:

  • 这部分app没有访问状态,如果有其他方法?另外,我更新了问题以显示更多代码。
  • 是的,我意识到你不能像你声明的那样在组件上使用状态。您可以在每个数据对象上添加一个“打开”属性(在加载后),然后将一个函数从 App 传递到 AccordionElement,它会更改给定对象的打开属性?我现在已经下班了,但是当我回到笔记本电脑前(约 1 小时)时,我可以写出一个解决方案。
  • 您必须在某处管理状态,因此只需以上面的答案为例,将其放在AccordionElement Accordion 中。我会说将其保存在Accordion 中的最佳位置,因为如果您当时只想保持一个打开状态,则可以轻松关闭其他位置。为此,您必须将两者之一作为 React 类而不是纯函数。您可以通过 redux 通过全局状态对其进行管理,并保持两个组件不变
  • @ragebunny 今晚试图解决这个问题,同时仍然使用无状态组件;这很难。我认为对于至少其中一个组件(可能是Acordion,所以你可以按照上面 Max 的建议进行操作),如果可能的话,你应该切换到普通的React.Component,然后从那里开始。无状态组件很棒,但不能设置状态或使用组件生命周期方法是非常有限的,在这种情况下不合适(在我看来)。我可能会在某个时候再试一次,但没有承诺。
  • @ragebunny 示例更新为(希望)工作示例。让我知道它是否有效。
猜你喜欢
  • 2022-11-09
  • 1970-01-01
  • 2022-12-11
  • 2021-04-26
  • 2021-11-12
  • 2015-12-05
  • 1970-01-01
  • 2020-10-07
  • 2019-09-26
相关资源
最近更新 更多