【问题标题】:Not able to re-render the page after updating redux state更新 redux 状态后无法重新渲染页面
【发布时间】:2023-03-19 12:20:01
【问题描述】:

在这里,我在“/dashboard/gdrive”中获取 google 驱动器文件列表。还有一个上传新文件的事件。上传 redux 状态时显示新文件存储在状态中,但在重新渲染时我无法访问存储状态。

这是代码块

import React, { Component } from 'react';
import PropTypes from "prop-types";
import {connect} from "react-redux";
import {logoutUser} from "./../../actions/authActions.js";
import {syncCloud} from "./../../actions/cloudActions.js";
import {uploadFile} from "./../../actions/cloudActions.js";

class Gdrive extends Component {
    constructor(){
        super();
        this.state={
            file: null
        }
        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
        this.handleCancelEvent = this.handleCancelEvent.bind(this);
    }
    onChange(e){
        this.setState({
            file: e.target.files[0]
        });
    }
    onSubmit(e){
        e.preventDefault();
        const data = new FormData();
        data.append('filename', this.state.file);
        this.props.uploadFile(data);
    }
    handleCancelEvent(){
        this.setState({
            file: null
        })
    }
    render() {    
    return (
        <div>
            <table>
                <thead>
                    <tr><th>fileid</th><th>filename</th></tr>
                </thead>
                <tbody>
                    {this.props.cloud.files.data.map(file =>(
                        <tr>
                            <td>{file.id}</td>
                            <td>{file.name}</td>
                        </tr>
                    ))}
                </tbody>
            </table>
            <fieldset>
                <form noValidate onSubmit={this.onSubmit}>
                <div>
                    <label>filename</label>
                    <input type="file" onChange={this.onChange} name= "filename"></input>
                </div>
                <div>
                    <button type="submit">Upload</button> 
                    <button onClick={this.handleCancelEvent}>Cancel</button>
                </div>
                </form>
            </fieldset>
        </div>
    )
  }
}
Gdrive.propTypes = {
    logoutUser: PropTypes.func.isRequired,
    auth: PropTypes.object.isRequired
  };
const mapStateToProps = state => ({
    auth: state.auth,
    cloud: state.cloud
});
export default connect(
    mapStateToProps,
    { logoutUser, syncCloud, uploadFile }
  )(Gdrive);

这里是 uploadFile 操作

export const uploadFile = (file) => dispatch => {
axios.post('/gdrive/upload', file)
.then(rslt => {
    dispatch({
        type: UPLOAD_FILE,
        payload: {id: rslt.data.fileid, name: rslt.data.filename}
    })
})
.catch(err => {
    dispatch({
        type: GET_ERRORS,
        payload: err
    })
});

}

这里是减速器

import {SYNC_CLOUD, UPLOAD_FILE} from './../actions/types';

const initialState = {
    files: {}
};

export default function(state=initialState, action){
    switch(action.type){
        case SYNC_CLOUD:
            return{
                ...state,
                files: action.payload
            };
        case UPLOAD_FILE: 
            return{
                ...state,
                files: state.files.data.concat(action.payload),
            };
        default: 
            return state;
    }
}

error screenshot

【问题讨论】:

  • 你也可以发布你的减速器吗?文件上传api调用成功后是否出现此错误?
  • 你在reducer中追加到数组吗?错误是因为this.props.cloud.files不是他们上传后的数组
  • @santosh 我已经发布了减速器。我得到了错误的位置最初文件存储在文件->数据->{}中,但是在上传新文件后,状态更改为文件->{}现在我只想更改文件->数据而不是文件。你能告诉如何改变状态的一部分
  • 我无法在评论中写下所有内容,这就是我在答案中发布的原因。我不明白为什么 files 是 object 。如果您从哪里解释文件具有数据属性,我将相应地修改答案。另外,我不确定 SYNC_CLOUD 操作。看起来这两个动作都做同样的事情,连接现有的文件数组。你能解释一下吗?如果是,那么应该只有一个动作说,UPDATE_FILES,它只是简单地执行 [...state, action.payload]。如果你解释一下,我会修改答案
  • @santosh 文件来自 google drive api 的结果。 SYNC_CLOUD 将用户连接到谷歌驱动器并通过创建 redux 状态在仪表板上列出文件,而 UPLOAD_FILES 允许用户在驱动器上上传新文件并更新状态。

标签: node.js reactjs redux


【解决方案1】:

我认为你的减速器映射错误。这里的关键是将初始状态声明为空文件而不是空对象。并且还将现有数组与来自 api(payload) 的响应连接起来。

把你的reducer改成这样:

 import {SYNC_CLOUD, UPLOAD_FILE} from './../actions/types';

const initialState = {
    files: []
};

export default function(state=initialState, action){
    switch(action.type){
        case SYNC_CLOUD:
            return{
                ...state,
                files: action.payload
            };
        case UPLOAD_FILE: 
            return{
                [...state, action.payload],
            };
        default: 
            return state;
    }
}

并将渲染函数改为

<tbody>
       {this.props.cloud.files.map(file =>(
            <tr>
                 <td>{file.id}</td>
                  <td>{file.name}</td>
              </tr>
                ))}
 </tbody>

【讨论】:

    【解决方案2】:

    mapDispatchToProps 参数到connect 需要是一个函数。要么做这样的事情

    const mapDispatchToProps= dispatch => bindActionCreators(
        { logoutUser, syncCloud, uploadFile },
        dispatch
    )
    

    或者,将null 传递为您的mapDispatchToProps,并在您的组件中使用类似this.props.dispatch(uploadFile(data)) 的动作创建器

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-03
      • 2019-05-07
      • 2020-07-12
      相关资源
      最近更新 更多