首页 > 解决方案 > 来自redux的array.map不会在第一次加载react组件时返回数据

问题描述

嗨,我一直在尝试一些反应和电子,我只是想制作一个媒体播放列表类型的应用程序,但我在使用 Redux 时遇到了一些问题

所以我已经设置了动作并且它们做了一些工作,但是由于某种原因,在组件的第一次初始加载时,我用来在列表中显示所有结果的 array.map 不会实际呈现。

我已经让控制台输出结果,当组件渲染渲染功能的第一遍时,初始状态为空,然后在第二遍时控制台记录正确的输出,但 array.map 仍然没有输出任何东西。

在此处输入图像描述

然后,当我在编辑器中保存文件(热重载已打开)时,我将从 array.map 获取要渲染的项目

在此处输入图像描述

我无法弄清楚我是否在某个地方犯了愚蠢的错误,或者我只是在做错事。所以我希望也许有人能够对这种情况有所了解。

这是我的组件文件,其中的 array.map 函数不起作用

interface Props {
  songs?: any;
  receiveMedia?: Function;
}

interface SongState {}

export default class Songs extends React.Component<Props, SongState> {
  private initLoad = 0;
  constructor(props: Props) {
    super(props);
    this.state = {};

    this.getThumbnailRender = this.getThumbnailRender.bind(this);
  }

  componentDidMount() {
    this.props.receiveMedia && this.props.receiveMedia();
  }

  getThumbnailRender() {
    console.log(this.props.songs);
    if (this.props.songs.Media.songs !== null) {
      return this.props.songs.Media.songs.map((media: any) => {
        if (media.extension !== "mp4") {
          return (
            <li
              className={css.thumbNail}
              id={media.id}
              key={`${"media_thumb_"}${media.id}`}
            >
              <img src={mp3} />
              <span className={css.floatingText}>{media.fileName}</span>
            </li>
          );
        } else {
          return (
            <li
              className={css.thumbNail}
              id={media.id}
              key={`${"media_thumb_"}${media.id}`}
            >
              <img src={media.filePath} />
              <span className={css.floatingText}>{media.fileName}</span>
            </li>
          );
        }
      });
    }
    return <div>You haven't added any songs</div>;
  }

  render() {
    return (
      <div className={css.container}>
        <h1>Songs</h1>
        <div className={css.songHolder}>
          <ul>{this.getThumbnailRender()}</ul>
        </div>
      </div>
    );
  }
}

我很确定 Action 和 reducer 文件在以后工作时很好,但我会包括它们以防我犯了一个愚蠢的错误

行动.ts

import { Songs } from "../../Models";
var fs = require("fs");

export enum ActionTypes {
  MEDIA_RECEIVED = "[Media] MEDIA_RECEIVED"
}

export interface MediaReceived {
  type: ActionTypes.MEDIA_RECEIVED;
  payload: {
    globals: Songs;
  };
}

export function mediaReceived(json: any): MediaReceived {
  return {
    type: ActionTypes.MEDIA_RECEIVED,
    payload: {
      globals: json
    }
  };
}

function loadInCurrentSongList() {
  var obj: Songs = {
    //@ts-ignore
    songs: []
  };
  fs.readFile("saveFile.json", "utf-8", (err: any, data: any) => {
    if (err) {
      alert("An error ocurred reading the file :" + err.message);
      return;
    }
    const newData = JSON.parse(data);
    if (newData.songs.length > 0) {
      newData.songs.map((song: any) => {
        obj.songs.push(song);
      });
    }
  });
  return obj;
}

export function receiveMedia() {
  return (dispatch: Function) => {
    dispatch(mediaReceived(loadInCurrentSongList()));
  };
}

export type Action = MediaReceived;

减速器.ts

import { Songs } from "../../Models";
import { Action, ActionTypes } from "./Actions";

export interface State {
  songs: Songs | null;
}

export const initialState: State = {
  songs: null
};

export function reducer(state: State = initialState, action: Action) {
  if (action.type === ActionTypes.MEDIA_RECEIVED) {
    return Object.assign({}, state, action.payload.globals);
  } else {
    return state;
  }
}

非常感谢 :)

标签: reactjsreduxreact-reduxelectron

解决方案


因为fs.readFile是异步的,并且传递给它的回调会在稍后 fs 操作完成时执行,它是在填充歌曲之前obj返回的,因此何时调度仍然是空的。您的调试器有点愚弄您,因为它显示了在回调中填充后的更新值。loadInCurrentSongListmediaReceivedsongsobjfs.readFile

热重载之所以有效,是因为它强制重新渲染而不破坏状态,此时obj已在fs.readFile回调内部发生了变异。

这是使用 Promise 管理异步性质的一种选择,fs.readFile这样您就可以等待它完成而不是改变objloanInCurrentSongList. 对打字稿不太熟悉,因此您可能必须更新类型:

function loadInCurrentSongList() {
  return new Promise(resolve => {
    fs.readFile("saveFile.json", "utf-8", (err: any, data: any) => {
      var obj: Songs = {
        //@ts-ignore
        songs: []
      };
      if (err) {
        alert("An error ocurred reading the file :" + err.message);
        resolve(obj);
        return;
      }
      const newData = JSON.parse(data);
      if (newData.songs.length > 0) {
        newData.songs.map((song: any) => {
          obj.songs.push(song);
        });
      }
      resolve(obj);
    });
}

export function receiveMedia() {
  return (dispatch: Function) => {
    loadInCurrentSongList().then(songList => {
      dispatch(mediaReceived(songList));
    }
  };
}

推荐阅读