【问题标题】:React Modal Updater doesn't refresh page after setState()在 setState() 之后 React Modal Updater 不刷新页面
【发布时间】:2021-07-04 16:38:18
【问题描述】:

有人建议我浅复制一个对象,因为仅使用= 符号复制状态对象会“指向”旧状态。

现在,我知道了:我的屏幕上有一个列表,其中的每个项目都是状态数组中的一个元素。每个项目都有自己的“更改”按钮,当按下该按钮时,会打开一个反应模式,其中包含所有项目信息到文本输入中,所以我可以更改它并按下“更新”按钮模态的。按下后,模态框应该关闭并且列表应该被刷新,但是最后这件事没有发生。

这是整个组件代码:

import React, { useContext, useEffect, useState } from 'react';
import { ThemeContext } from '../../providers/ThemeContext';
import axios from '../../services/axios';
import './styles.css';
import Modal from 'react-modal';
import { Divider } from '@material-ui/core';

Modal.setAppElement('#root')
function AllInOneProjectPage() {
    const [projects, setProjects] = useState<any[]>([]);
    const { theme } = useContext(ThemeContext);
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [id, setId] = useState('');
    const [title, setTitle] = useState('');
    const [url, setUrl] = useState('');
    const [techs, setTechs] = useState<any[]>([]);
    
    const openModal = (idModal: string, title: string, url: string, techs: any[]) => {
        setId(idModal);
        setTitle(title);
        setUrl(url);
        setTechs(techs);
        setIsModalOpen(true);
    }

    const closeModal = () => {
        setIsModalOpen(false);
    }

    const updateProjects = async () => {
        const res = await axios.get('list');
        res.data.status === 1 && setProjects(res.data.projects);
    };
    
    useEffect(() => {
        updateProjects();
    }, []);

    const onUpdateProject = async () => {
        const newTitle = (document.getElementById(`modal_title_${id}`) as HTMLInputElement)?.value;
        const newUrl = (document.getElementById(`modal_url_${id}`) as HTMLInputElement)?.value;
        const techsArray = (document.getElementById(`modal_techs_${id}`) as HTMLInputElement)?.value;
        const filteredTechs = techsArray.split(',').filter(tech => {
            if(tech !== '')
                if(tech !== ' ')
                    return tech;
        });
        
        await axios.patch(`update/${id}`, { title: newTitle, url: newUrl, techs: filteredTechs });
        setProjects(projects.map(p => id === p.id ? { ...p, title: newTitle, url: newUrl, techs: filteredTechs } : p));
        setIsModalOpen(false);
        console.log(projects.map(p => id === p.id ? { ...p, title: newTitle, url: newUrl, techs: filteredTechs } : p));
    };
    
    return (
        <div style={{
            width: '100vw',
            minHeight: 'calc(100vh - 64px)',
            backgroundColor: theme.bg,
            margin: '0',
            display: 'flex',
            justifyContent: 'space-around',
            flexWrap: 'wrap'
        }}>
            { projects && projects.map((p, i) => <div key={p.id} style={{
                display: 'flex',
                flexDirection: 'column',
                width: '550px',
                height: '300px',
                border: '1px solid blue',
                margin: '50px'
            }}>
                <div style={{ backgroundColor: 'green', height: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'space-around' }}>
                    <div style={{display: 'flex', flexDirection: 'column', width: '80%'}}>
                        <h4>Title:</h4>
                        <input type="text" name="title" disabled defaultValue={ p.title }/>
                    </div>
                    <div style={{display: 'flex', flexDirection: 'column', width: '80%'}}>
                        <h4>URL:</h4>
                        <input type="text" name="url" disabled defaultValue={ p.url }/>
                    </div>
                    <div style={{display: 'flex', flexDirection: 'column', width: '80%'}}>
                        <h4>Techs:</h4>
                        <input type="text" name="techs" disabled defaultValue={ p.techs.map((t: any) => t) }/>
                    </div>
                    <a style={{textDecoration: 'underline', color: 'darkblue', cursor: 'pointer' }} onClick={() => openModal(p.id, p.title, p.url, p.techs)}>Alterar</a>
                </div>
            </div>) }

            <Modal isOpen={isModalOpen} style={{
                content: {
                    display: 'flex',
                    flexDirection: 'column',
                    maxWidth: '450px',
                    height: '280px',
                    margin: 'auto',
                    backgroundColor: 'lightgrey'
                },
                overlay: {
                    backgroundColor: 'rgba(0, 0, 0, 0.85)'
                }
            }}>
                <div className="modal-header" style={{ display: 'flex', justifyContent: 'space-between' }}>
                    <h1>Edit { title }</h1>
                    <button onClick={closeModal} style={{ width: '90px', height: '20px', margin: 'auto 0' }}>Close</button>
                </div>
                <Divider />
                <div style={{ width: '80%', margin: '10px auto 0 auto'}}>
                    <h2>Title: </h2>
                    <input type="text" name="title" id={`modal_title_${id}`} defaultValue={ title } style={{ width: '90%' }}/>
                </div>
                <div style={{ width: '80%', margin: '10px auto 0 auto'}}>
                    <h2>URL: </h2>
                    <input type="text" name="title" id={`modal_url_${id}`} defaultValue={ url } style={{ width: '90%' }}/>
                </div>
                <div style={{ width: '80%', margin: '10px auto 0 auto'}}>
                    <h2>Techs: </h2>
                    <input type="text" name="title" id={`modal_techs_${id}`} defaultValue={ techs } style={{ width: '90%' }}/>
                </div>
                <button onClick={ () => onUpdateProject() } style={{ width: '90px', margin: '10px auto 0 auto' }}>Update</button>
            </Modal>
        </div>
    );
}

export default AllInOneProjectPage;

【问题讨论】:

  • 感谢@AjeetShah 的澄清,我会这样做的!但我认为他会被标记,我遵循了 stachexchange 上的“指南”,上面说...无论如何,我现在正在做,再次感谢:D
  • 您的projects 状态是否真的 没有更新,或者您只是在状态更新后在控制台日志中看到当前尚未更新的状态? IE。 setProjects(projects.map( .... )); 然后console.log(projects.map( .... )); 日志将是当前状态。
  • 控制台日志确实显示了已经更新的数组,但是屏幕上的主数组应该在模态关闭后立即更新。该日志有效,因为我在其上使用了与地图相同的逻辑
  • 除了尝试功能状态更新 (setProjects(projects =&gt; projects.map( .... )) 我有点难过。认为您可以创建一个 running 代码框来重现我们可以在其中进行调试的更新问题?
  • 哦,抱歉,我有点忙。我相信我能够在您的沙盒中重现您的问题,但还没有机会进行调查,尽管我会在这里稍等片刻。 Ajeet,如果您已经在看这个,请随时继续。

标签: reactjs use-state react-dom react-modal


【解决方案1】:

问题

我认为这个问题很简单;您已将defaultValue 用于AllInOneProjectPage 组件上的禁用输入。当输入使用 defaultValue 属性时,它会使它们成为不受控制的输入,这意味着它们不会响应任何外部变化,也不受任何状态的控制。

解决方案

使用 value 属性将这些输入转换为受控输入。

{projects &&
  projects.map((p, i) => (
    <div key={p.id} style={outerDivProject}>
      <div style={projectFields}>
        <h4>Title:</h4>
        <input type="text" name="title" disabled value={p.title} /> // <-- now controlled
      </div>

      <div style={projectFields}>
        <h4>URL:</h4>
        <input type="text" name="url" disabled value={p.url} /> // <-- now controlled
      </div>

      <div style={projectFields}>
        <h4>Techs:</h4>
        <input
          type="text"
          name="techs"
          disabled
          value={p.techs.map((t: any) => t)} // <-- now controlled
        />
      </div>

      <p
        style={changeButtonStyles}
        onClick={() => openModal(p.id, p.title, p.url, p.techs)}
      >
        Alterar
      </p>
    </div>
  ))}

分叉演示

【讨论】:

  • 老兄,我真的很想知道为什么有些东西一开始根本不起作用哈哈哈......我记得有一次我尝试使用道具value,然后反应只是给我一个错误要求改用defaultValue,所以不知何故它一直在我的脑海里,我只是遵循那个“命令”... Rep++++ 谢谢人:D
猜你喜欢
  • 2018-06-11
  • 1970-01-01
  • 1970-01-01
  • 2022-11-10
  • 1970-01-01
  • 1970-01-01
  • 2020-08-28
  • 2019-04-24
  • 2019-12-24
相关资源
最近更新 更多