首页 > 解决方案 > 如何在反应中折叠子组件中的手风琴

问题描述

我正在创建一个页面来更新我正在使用 NextJS 构建的电子商务网站上的产品详细信息,并且我将图像上传部分嵌套在单个项目页面的手风琴内。上传图片后,我想清除上传表单并关闭手风琴。它正在关闭我遇到问题的手风琴。

ImageUploadAccordion.js:

import React, {useRef} from 'react';
import {Accordion} from 'react-bootstrap'
import ImageUpload from './ImageUpload'

export default function ImageUploadAccordion({ item }) {
  
  const accordionRef = useRef(null);
  const toggleAccordion = () => {
    accordionRef.current.click();
  }
    return (
      <Accordion ref={accordionRef} defaultActiveKey="0">
      <Accordion.Item eventKey="1">
        <Accordion.Header>
          <span className="btn btn-outline-success">Upload Images</span>
        </Accordion.Header>
        <Accordion.Body>
          <ImageUpload 
            toggle={toggleAccordion}
            item={item}
          />
          
        </Accordion.Body>
      </Accordion.Item>
    </Accordion>
    )
}

图片上传.js:

import React, {useState} from 'react';
import { useRouter } from 'next/router'

export default function ImageUpload({ item, toggle }) {
    
    const router = useRouter()
    const [images, setImages] = useState([])
    const [imageURLS, setImageURLS] = useState([])
    const [tags, setTags] = useState([])
    const [theInputKey, setTheInputKey] = useState('')

    const uploadImageToClient = (event) => {
   
      if (event.target.files && event.target.files[0]) {
        setImages((imageList) => [...imageList, {"index": images.length, "data": event.target.files[0]}]);
        setImageURLS((urlList) => [
            ...urlList,
            URL.createObjectURL(event.target.files[0])
          ]);
      }
      let randomString = Math.random().toString(36);
      setTheInputKey(randomString)
    };
  
    const uploadTagToClient = (e) => {
      if (event.target.value) {
        const name = e.target.getAttribute("name")
        // const i = event.target.value;
        // document.getElementById("image-upload")
        setTags((tagList) => [...tagList, {"name": name, "tag": e.target.value}]);
      }
    };

    const removeImage = (name) => {
      // debug
      alert(`Trying to remove image index ${name}`)
      let newImages = []
      let newTags = []
      setImages(images.filter(image => image.data.name !== name));
      setTags(tags.filter(tag => tag.name !== name));
    }

    const uploadToServer = async (e) => {
      const body = new FormData()
      images.map((file, index) => {
        body.append(`file${index}`, file.data);
      });
      // Use the filenames as keys then we can retrieve server side once we have the images
      tags.map((tag, index) => {
        body.append(tag.name, tag.tag)
      })
      
      const response = await fetch("/api/file", {
        method: "POST",
        "Content-Type": "multipart/form-data",
        body
      })

      var message = await response.json();
      alert(message['message'])
      setImages([])
      setTags([])
      toggle()
    
   
    };
    
    const openImageUploadDialogue = () =>{
      document.getElementById("image-upload").click()
    }

    return (
  
        <div className="container">
          <input style={{display:'none'}} accept="image/*" id="image-upload" type="file" key={theInputKey || '' } className="btn btn-outline-success-inverse" onChange={uploadImageToClient} />
          <button className="btn btn-outline-success-inverse" onClick={openImageUploadDialogue} >
            Add Image 
          </button>
          <hr className = "text-pink"/>
          <div className="row">
            <div className="col d-flex flex-wrap">
              {images.map((file, index) => {
              return (
                <div className="div p-1" key={file.data.name}>
                    <p className="text-pink">{file.data.name}</p>
                    <p>Tag</p>
                    <input type="text" name={file.data.name} id={`${file.data.name}`} onChange={uploadTagToClient} />
                    <img src={imageURLS[index]} height="200" width="150" />
                    <div className="btn btn-outline-success-inverse" onClick={ () =>removeImage(file.data.name)}>Remove Image</div>
                </div>
                );
              })}
              </div>
              <button
                className="btn btn-outline-success-inverse"
                type="submit"
                onClick={uploadToServer}
              >
                Upload Images
              </button>
            </div>
        </div> 
    );
}

根据类似问题的另一个答案,我尝试使用 useRef 创建对手风琴的引用,以及使用此引用来激活单击事件的函数,该函数已传递给 ImageUpload 组件,但它似乎不起作用我不确定为什么。

任何帮助总是很感激:-)

标签: javascriptreactjsnext.js

解决方案


我相信你有错误的目标ref,更新它以定位自动生成的按钮来包装标题内容。

<h2 class="accordion-header"><button type="button" aria-expanded="true" class="accordion-button"><span class="btn btn-outline-success">Upload Images</span></button></h2>

基本示例:

export default function ImageUploadAccordion({ item }) {
   const accordionRef = useRef(null);
  
   const toggleAccordion = () => {
     accordionRef.current.querySelector('button').click();
   }

   return (
      <Accordion  defaultActiveKey="0">
      <Accordion.Item eventKey="1">
        <Accordion.Header ref={accordionRef}>
          <span className="btn btn-outline-success">Upload Images</span>
        </Accordion.Header>
        <Accordion.Body>
          <ImageUpload 
            toggle={toggleAccordion}
            item={item}
          />
          
        </Accordion.Body>
      </Accordion.Item>
    </Accordion>
    )
}

推荐阅读