React native 重复保存保存多个数据

React native 重复保存保存多个数据,react-native,redux,React Native,Redux,我正在利用我的应用程序获取用户设备上的音乐文件,我正在利用redux persist,这样当音乐在用户手机上加载一次,用户返回应用程序时,它只需检查不在曲目状态数组中的新音乐,而不必重新扫描所有音乐,它只会在后台检查新音乐,但状态通常包含两个数据(通常会重新加载音乐,会显示音乐1-5,然后是音乐1-10),并且不会加载手机上的所有音乐,只是中途停止,当我使用正常状态时,例如this.setState用户手机上的所有音乐通常都会加载。请问我可能做错了什么 下面是我的代码 Store-index.j

我正在利用我的应用程序获取用户设备上的音乐文件,我正在利用redux persist,这样当音乐在用户手机上加载一次,用户返回应用程序时,它只需检查不在
曲目
状态数组中的新音乐,而不必重新扫描所有音乐,它只会在后台检查新音乐,但状态通常包含两个数据(通常会重新加载音乐,会显示音乐1-5,然后是音乐1-10),并且不会加载手机上的所有音乐,只是中途停止,当我使用正常状态时,例如
this.setState
用户手机上的所有音乐通常都会加载。请问我可能做错了什么 下面是我的代码

Store-index.js

import { createStore } from "redux";
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' 
import rootReducer from "../reducers/index";
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const persistConfig = {
    key: 'root',
    storage,
  //  stateReconciler: autoMergeLevel2,
    timeout: 0,
  }
const persistedReducer = persistReducer(persistConfig, rootReducer)
export default () => {
  let store = createStore(persistedReducer)
  let persistor = persistStore(store)
  return { store, persistor }
}    
export const addSong = song => ({type:
    "ADD_SONG", payload: song
});
export const RESET_ACTION = {
    type: "RESET"
}
import{ADD_SONG,RESET} from "../constants/action-types";
const initialState = {
    tracks: []
};
const rootReducer = (state = initialState, action) => {
    switch (action.type){
        case ADD_SONG:
        let index = state.tracks.findIndex(tracks => tracks.id == action.payload.id);    
        if(index != -1){
            return state;
        }else{
        return { 
            ...state,
            tracks: [...state.songs, action.payload]
        }
        }
        case RESET:
        return initialState;
        default:
            return state
    }
}
export default rootReducer;
import React, { Component } from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    Image,
    Dimensions,
    StatusBar,
    ScrollView,
    View,
    DeviceEventEmitter,
    FlatList,
    ActivityIndicator,
    AsyncStorage
} from 'react-native';
import Splash from './components/Splash';
import Home from './components/Home';
import MusicFiles from 'react-native-get-music-files';
import Permissions from 'react-native-permissions';
import { PersistGate } from 'redux-persist/integration/react';
//import store from "./store/index";
import index from './store/index';
const {store, persistor} = index();
import {connect, Provider} from 'react-redux';
import {addSong, RESET_ACTION
} from "./actions/index";

const mapStateToProps = state => {
    return {
        tracks: state.tracks
    };
};
const mapDispatchToProps = dispatch => {
    return {
      addSong: song => dispatch(addSong(song)),
      RESET_ACTION
    };
};

class reduxApp extends Component{
    millisToMinutesAndSeconds(millis) {
        var minutes = Math.floor(millis / 60000);
        var seconds = ((millis % 60000) / 1000).toFixed(0);
        return (seconds == 60 ? (minutes+1) + ":00" : minutes + ":" + (seconds < 10 ? "0" : "") + seconds);
      }
           componentDidMount() {
            this.props.RESET_ACTION;   
            this.setState({loaded: false});
            if(this.props.songs && this.props.songs.length > 0){
            this.setState({loaded: true})    
            }else{
            this.musicGetter();    
            }


           }
           musicGetter(){
            Permissions.request('storage').then(response => {
                this.setState({ photoPermission: response })
              })
              MusicFiles.getAll({
                  id : true,
                  blured : false,
                  artist : true,
                  duration : true, //default : true
                  cover : true, //default : true,
                  title : true,
                  cover : true,
                  batchNumber : 1, //get 5 songs per batch
                  minimumSongDuration : 10000, //in miliseconds,
                  fields : ['title','artwork','duration','artist','genre','lyrics','albumTitle']
                })
           }
           componentWillMount() {
        /*    DeviceEventEmitter.addListener(
                'onBatchReceived',
                (params) => {
                    this.setState({songs : [
                        ...this.state.songs,
                        ...params.batch
                    ]},this.setState({loaded: true}));
                }
            );*/
            DeviceEventEmitter.addListener(
                'onBatchReceived',
                (params) => {
                    console.log(params.batch);
                    this.props.addSong(params.batch);
                    this.setState({loaded: true});
                }, 
            );

        }
      async  asynccer(){

            try {
                await AsyncStorage.setItem('@MySuperStore:songs', JSON.stringify(this.state.songs));
              } catch (error) {
                // Error saving data
              }
        }
    constructor(props) {
        super(props);
        this.state = {
            timePassed: false,
            photoPermission: '',
            songs: [], 
            loaded: true,
            loading: false
        };
    }
  render() {
    if (!this.state.loaded) {
        return (
            <Splash/>
           );
    } else {
        return (
            <View style={styles.linearGradient}>
            <Provider store={store}>
            <PersistGate loading={null} persistor={persistor}>
            <Home songs={this.props.tracks}/>
            </PersistGate>
            </Provider>
            </View>
        );

    }
}
}
function connectWithStore(store, WrappedComponent, ...args) {
    var ConnectedWrappedComponent = connect(...args)(WrappedComponent)
    return function (props) {
      return <ConnectedWrappedComponent {...props} store={store} />
    }
  }
  const App = connectWithStore(store, reduxApp,mapStateToProps, mapDispatchToProps);
  export default App;
render() { 
        const lyrics = this.props.songs.map((song, index) =>
        <View style={styles.musicBox} key={index}>
        <View style={{width: 57, height: 59, borderRadius: 9, marginLeft: 15}}>
         <Image resizeMode="contain"
         style={{alignSelf: 'center', borderRadius: 9, width: 57, height: 59}}
          source={{uri: song[0].cover}}/>
          </View>
         <View style={styles.TextBox}>
          <Text 
          numberOfLines={1} 
          style={{fontFamily: 'nexaBold', fontSize: 20, color: 'white', flex: 1}}>
              {song[0].title}
          </Text>
          <View style={{flexDirection: 'row', }}>
          <Text 
          numberOfLines={1} 
          style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D', 
          marginRight: 5, }}>
              {song[0].author}
          </Text>
          <View style={{alignSelf:'center',width: 2, height: 2, borderRadius: 1, backgroundColor: '#917D7D',marginRight: 5}}>

          </View>
          <Text style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D'}}>
              {this.millisToMinutesAndSeconds(song.duration)}
          </Text></View>
         </View>
        </View>         
        );

        const music = 
            <ScrollView overScrollMode={'never'} keyboardShouldPersistTaps='always'>
            {lyrics}</ScrollView>;
        const shadowOpt = {
            color: "#000",
            border: 12,
            opacity: '0.08',
            radius: 12,
            x: 0,
            y: 1,
        };          
        return (
            <View style={{flex: 1}}>
            <View style={styles.linearGradient}>                                      
                {music}
                </View>
            </View>
        );
    }
}
操作-index.js

import { createStore } from "redux";
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' 
import rootReducer from "../reducers/index";
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const persistConfig = {
    key: 'root',
    storage,
  //  stateReconciler: autoMergeLevel2,
    timeout: 0,
  }
const persistedReducer = persistReducer(persistConfig, rootReducer)
export default () => {
  let store = createStore(persistedReducer)
  let persistor = persistStore(store)
  return { store, persistor }
}    
export const addSong = song => ({type:
    "ADD_SONG", payload: song
});
export const RESET_ACTION = {
    type: "RESET"
}
import{ADD_SONG,RESET} from "../constants/action-types";
const initialState = {
    tracks: []
};
const rootReducer = (state = initialState, action) => {
    switch (action.type){
        case ADD_SONG:
        let index = state.tracks.findIndex(tracks => tracks.id == action.payload.id);    
        if(index != -1){
            return state;
        }else{
        return { 
            ...state,
            tracks: [...state.songs, action.payload]
        }
        }
        case RESET:
        return initialState;
        default:
            return state
    }
}
export default rootReducer;
import React, { Component } from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    Image,
    Dimensions,
    StatusBar,
    ScrollView,
    View,
    DeviceEventEmitter,
    FlatList,
    ActivityIndicator,
    AsyncStorage
} from 'react-native';
import Splash from './components/Splash';
import Home from './components/Home';
import MusicFiles from 'react-native-get-music-files';
import Permissions from 'react-native-permissions';
import { PersistGate } from 'redux-persist/integration/react';
//import store from "./store/index";
import index from './store/index';
const {store, persistor} = index();
import {connect, Provider} from 'react-redux';
import {addSong, RESET_ACTION
} from "./actions/index";

const mapStateToProps = state => {
    return {
        tracks: state.tracks
    };
};
const mapDispatchToProps = dispatch => {
    return {
      addSong: song => dispatch(addSong(song)),
      RESET_ACTION
    };
};

class reduxApp extends Component{
    millisToMinutesAndSeconds(millis) {
        var minutes = Math.floor(millis / 60000);
        var seconds = ((millis % 60000) / 1000).toFixed(0);
        return (seconds == 60 ? (minutes+1) + ":00" : minutes + ":" + (seconds < 10 ? "0" : "") + seconds);
      }
           componentDidMount() {
            this.props.RESET_ACTION;   
            this.setState({loaded: false});
            if(this.props.songs && this.props.songs.length > 0){
            this.setState({loaded: true})    
            }else{
            this.musicGetter();    
            }


           }
           musicGetter(){
            Permissions.request('storage').then(response => {
                this.setState({ photoPermission: response })
              })
              MusicFiles.getAll({
                  id : true,
                  blured : false,
                  artist : true,
                  duration : true, //default : true
                  cover : true, //default : true,
                  title : true,
                  cover : true,
                  batchNumber : 1, //get 5 songs per batch
                  minimumSongDuration : 10000, //in miliseconds,
                  fields : ['title','artwork','duration','artist','genre','lyrics','albumTitle']
                })
           }
           componentWillMount() {
        /*    DeviceEventEmitter.addListener(
                'onBatchReceived',
                (params) => {
                    this.setState({songs : [
                        ...this.state.songs,
                        ...params.batch
                    ]},this.setState({loaded: true}));
                }
            );*/
            DeviceEventEmitter.addListener(
                'onBatchReceived',
                (params) => {
                    console.log(params.batch);
                    this.props.addSong(params.batch);
                    this.setState({loaded: true});
                }, 
            );

        }
      async  asynccer(){

            try {
                await AsyncStorage.setItem('@MySuperStore:songs', JSON.stringify(this.state.songs));
              } catch (error) {
                // Error saving data
              }
        }
    constructor(props) {
        super(props);
        this.state = {
            timePassed: false,
            photoPermission: '',
            songs: [], 
            loaded: true,
            loading: false
        };
    }
  render() {
    if (!this.state.loaded) {
        return (
            <Splash/>
           );
    } else {
        return (
            <View style={styles.linearGradient}>
            <Provider store={store}>
            <PersistGate loading={null} persistor={persistor}>
            <Home songs={this.props.tracks}/>
            </PersistGate>
            </Provider>
            </View>
        );

    }
}
}
function connectWithStore(store, WrappedComponent, ...args) {
    var ConnectedWrappedComponent = connect(...args)(WrappedComponent)
    return function (props) {
      return <ConnectedWrappedComponent {...props} store={store} />
    }
  }
  const App = connectWithStore(store, reduxApp,mapStateToProps, mapDispatchToProps);
  export default App;
render() { 
        const lyrics = this.props.songs.map((song, index) =>
        <View style={styles.musicBox} key={index}>
        <View style={{width: 57, height: 59, borderRadius: 9, marginLeft: 15}}>
         <Image resizeMode="contain"
         style={{alignSelf: 'center', borderRadius: 9, width: 57, height: 59}}
          source={{uri: song[0].cover}}/>
          </View>
         <View style={styles.TextBox}>
          <Text 
          numberOfLines={1} 
          style={{fontFamily: 'nexaBold', fontSize: 20, color: 'white', flex: 1}}>
              {song[0].title}
          </Text>
          <View style={{flexDirection: 'row', }}>
          <Text 
          numberOfLines={1} 
          style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D', 
          marginRight: 5, }}>
              {song[0].author}
          </Text>
          <View style={{alignSelf:'center',width: 2, height: 2, borderRadius: 1, backgroundColor: '#917D7D',marginRight: 5}}>

          </View>
          <Text style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D'}}>
              {this.millisToMinutesAndSeconds(song.duration)}
          </Text></View>
         </View>
        </View>         
        );

        const music = 
            <ScrollView overScrollMode={'never'} keyboardShouldPersistTaps='always'>
            {lyrics}</ScrollView>;
        const shadowOpt = {
            color: "#000",
            border: 12,
            opacity: '0.08',
            radius: 12,
            x: 0,
            y: 1,
        };          
        return (
            <View style={{flex: 1}}>
            <View style={styles.linearGradient}>                                      
                {music}
                </View>
            </View>
        );
    }
}
还原剂-index.js

import { createStore } from "redux";
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' 
import rootReducer from "../reducers/index";
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const persistConfig = {
    key: 'root',
    storage,
  //  stateReconciler: autoMergeLevel2,
    timeout: 0,
  }
const persistedReducer = persistReducer(persistConfig, rootReducer)
export default () => {
  let store = createStore(persistedReducer)
  let persistor = persistStore(store)
  return { store, persistor }
}    
export const addSong = song => ({type:
    "ADD_SONG", payload: song
});
export const RESET_ACTION = {
    type: "RESET"
}
import{ADD_SONG,RESET} from "../constants/action-types";
const initialState = {
    tracks: []
};
const rootReducer = (state = initialState, action) => {
    switch (action.type){
        case ADD_SONG:
        let index = state.tracks.findIndex(tracks => tracks.id == action.payload.id);    
        if(index != -1){
            return state;
        }else{
        return { 
            ...state,
            tracks: [...state.songs, action.payload]
        }
        }
        case RESET:
        return initialState;
        default:
            return state
    }
}
export default rootReducer;
import React, { Component } from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    Image,
    Dimensions,
    StatusBar,
    ScrollView,
    View,
    DeviceEventEmitter,
    FlatList,
    ActivityIndicator,
    AsyncStorage
} from 'react-native';
import Splash from './components/Splash';
import Home from './components/Home';
import MusicFiles from 'react-native-get-music-files';
import Permissions from 'react-native-permissions';
import { PersistGate } from 'redux-persist/integration/react';
//import store from "./store/index";
import index from './store/index';
const {store, persistor} = index();
import {connect, Provider} from 'react-redux';
import {addSong, RESET_ACTION
} from "./actions/index";

const mapStateToProps = state => {
    return {
        tracks: state.tracks
    };
};
const mapDispatchToProps = dispatch => {
    return {
      addSong: song => dispatch(addSong(song)),
      RESET_ACTION
    };
};

class reduxApp extends Component{
    millisToMinutesAndSeconds(millis) {
        var minutes = Math.floor(millis / 60000);
        var seconds = ((millis % 60000) / 1000).toFixed(0);
        return (seconds == 60 ? (minutes+1) + ":00" : minutes + ":" + (seconds < 10 ? "0" : "") + seconds);
      }
           componentDidMount() {
            this.props.RESET_ACTION;   
            this.setState({loaded: false});
            if(this.props.songs && this.props.songs.length > 0){
            this.setState({loaded: true})    
            }else{
            this.musicGetter();    
            }


           }
           musicGetter(){
            Permissions.request('storage').then(response => {
                this.setState({ photoPermission: response })
              })
              MusicFiles.getAll({
                  id : true,
                  blured : false,
                  artist : true,
                  duration : true, //default : true
                  cover : true, //default : true,
                  title : true,
                  cover : true,
                  batchNumber : 1, //get 5 songs per batch
                  minimumSongDuration : 10000, //in miliseconds,
                  fields : ['title','artwork','duration','artist','genre','lyrics','albumTitle']
                })
           }
           componentWillMount() {
        /*    DeviceEventEmitter.addListener(
                'onBatchReceived',
                (params) => {
                    this.setState({songs : [
                        ...this.state.songs,
                        ...params.batch
                    ]},this.setState({loaded: true}));
                }
            );*/
            DeviceEventEmitter.addListener(
                'onBatchReceived',
                (params) => {
                    console.log(params.batch);
                    this.props.addSong(params.batch);
                    this.setState({loaded: true});
                }, 
            );

        }
      async  asynccer(){

            try {
                await AsyncStorage.setItem('@MySuperStore:songs', JSON.stringify(this.state.songs));
              } catch (error) {
                // Error saving data
              }
        }
    constructor(props) {
        super(props);
        this.state = {
            timePassed: false,
            photoPermission: '',
            songs: [], 
            loaded: true,
            loading: false
        };
    }
  render() {
    if (!this.state.loaded) {
        return (
            <Splash/>
           );
    } else {
        return (
            <View style={styles.linearGradient}>
            <Provider store={store}>
            <PersistGate loading={null} persistor={persistor}>
            <Home songs={this.props.tracks}/>
            </PersistGate>
            </Provider>
            </View>
        );

    }
}
}
function connectWithStore(store, WrappedComponent, ...args) {
    var ConnectedWrappedComponent = connect(...args)(WrappedComponent)
    return function (props) {
      return <ConnectedWrappedComponent {...props} store={store} />
    }
  }
  const App = connectWithStore(store, reduxApp,mapStateToProps, mapDispatchToProps);
  export default App;
render() { 
        const lyrics = this.props.songs.map((song, index) =>
        <View style={styles.musicBox} key={index}>
        <View style={{width: 57, height: 59, borderRadius: 9, marginLeft: 15}}>
         <Image resizeMode="contain"
         style={{alignSelf: 'center', borderRadius: 9, width: 57, height: 59}}
          source={{uri: song[0].cover}}/>
          </View>
         <View style={styles.TextBox}>
          <Text 
          numberOfLines={1} 
          style={{fontFamily: 'nexaBold', fontSize: 20, color: 'white', flex: 1}}>
              {song[0].title}
          </Text>
          <View style={{flexDirection: 'row', }}>
          <Text 
          numberOfLines={1} 
          style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D', 
          marginRight: 5, }}>
              {song[0].author}
          </Text>
          <View style={{alignSelf:'center',width: 2, height: 2, borderRadius: 1, backgroundColor: '#917D7D',marginRight: 5}}>

          </View>
          <Text style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D'}}>
              {this.millisToMinutesAndSeconds(song.duration)}
          </Text></View>
         </View>
        </View>         
        );

        const music = 
            <ScrollView overScrollMode={'never'} keyboardShouldPersistTaps='always'>
            {lyrics}</ScrollView>;
        const shadowOpt = {
            color: "#000",
            border: 12,
            opacity: '0.08',
            radius: 12,
            x: 0,
            y: 1,
        };          
        return (
            <View style={{flex: 1}}>
            <View style={styles.linearGradient}>                                      
                {music}
                </View>
            </View>
        );
    }
}
App.js

import { createStore } from "redux";
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' 
import rootReducer from "../reducers/index";
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const persistConfig = {
    key: 'root',
    storage,
  //  stateReconciler: autoMergeLevel2,
    timeout: 0,
  }
const persistedReducer = persistReducer(persistConfig, rootReducer)
export default () => {
  let store = createStore(persistedReducer)
  let persistor = persistStore(store)
  return { store, persistor }
}    
export const addSong = song => ({type:
    "ADD_SONG", payload: song
});
export const RESET_ACTION = {
    type: "RESET"
}
import{ADD_SONG,RESET} from "../constants/action-types";
const initialState = {
    tracks: []
};
const rootReducer = (state = initialState, action) => {
    switch (action.type){
        case ADD_SONG:
        let index = state.tracks.findIndex(tracks => tracks.id == action.payload.id);    
        if(index != -1){
            return state;
        }else{
        return { 
            ...state,
            tracks: [...state.songs, action.payload]
        }
        }
        case RESET:
        return initialState;
        default:
            return state
    }
}
export default rootReducer;
import React, { Component } from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    Image,
    Dimensions,
    StatusBar,
    ScrollView,
    View,
    DeviceEventEmitter,
    FlatList,
    ActivityIndicator,
    AsyncStorage
} from 'react-native';
import Splash from './components/Splash';
import Home from './components/Home';
import MusicFiles from 'react-native-get-music-files';
import Permissions from 'react-native-permissions';
import { PersistGate } from 'redux-persist/integration/react';
//import store from "./store/index";
import index from './store/index';
const {store, persistor} = index();
import {connect, Provider} from 'react-redux';
import {addSong, RESET_ACTION
} from "./actions/index";

const mapStateToProps = state => {
    return {
        tracks: state.tracks
    };
};
const mapDispatchToProps = dispatch => {
    return {
      addSong: song => dispatch(addSong(song)),
      RESET_ACTION
    };
};

class reduxApp extends Component{
    millisToMinutesAndSeconds(millis) {
        var minutes = Math.floor(millis / 60000);
        var seconds = ((millis % 60000) / 1000).toFixed(0);
        return (seconds == 60 ? (minutes+1) + ":00" : minutes + ":" + (seconds < 10 ? "0" : "") + seconds);
      }
           componentDidMount() {
            this.props.RESET_ACTION;   
            this.setState({loaded: false});
            if(this.props.songs && this.props.songs.length > 0){
            this.setState({loaded: true})    
            }else{
            this.musicGetter();    
            }


           }
           musicGetter(){
            Permissions.request('storage').then(response => {
                this.setState({ photoPermission: response })
              })
              MusicFiles.getAll({
                  id : true,
                  blured : false,
                  artist : true,
                  duration : true, //default : true
                  cover : true, //default : true,
                  title : true,
                  cover : true,
                  batchNumber : 1, //get 5 songs per batch
                  minimumSongDuration : 10000, //in miliseconds,
                  fields : ['title','artwork','duration','artist','genre','lyrics','albumTitle']
                })
           }
           componentWillMount() {
        /*    DeviceEventEmitter.addListener(
                'onBatchReceived',
                (params) => {
                    this.setState({songs : [
                        ...this.state.songs,
                        ...params.batch
                    ]},this.setState({loaded: true}));
                }
            );*/
            DeviceEventEmitter.addListener(
                'onBatchReceived',
                (params) => {
                    console.log(params.batch);
                    this.props.addSong(params.batch);
                    this.setState({loaded: true});
                }, 
            );

        }
      async  asynccer(){

            try {
                await AsyncStorage.setItem('@MySuperStore:songs', JSON.stringify(this.state.songs));
              } catch (error) {
                // Error saving data
              }
        }
    constructor(props) {
        super(props);
        this.state = {
            timePassed: false,
            photoPermission: '',
            songs: [], 
            loaded: true,
            loading: false
        };
    }
  render() {
    if (!this.state.loaded) {
        return (
            <Splash/>
           );
    } else {
        return (
            <View style={styles.linearGradient}>
            <Provider store={store}>
            <PersistGate loading={null} persistor={persistor}>
            <Home songs={this.props.tracks}/>
            </PersistGate>
            </Provider>
            </View>
        );

    }
}
}
function connectWithStore(store, WrappedComponent, ...args) {
    var ConnectedWrappedComponent = connect(...args)(WrappedComponent)
    return function (props) {
      return <ConnectedWrappedComponent {...props} store={store} />
    }
  }
  const App = connectWithStore(store, reduxApp,mapStateToProps, mapDispatchToProps);
  export default App;
render() { 
        const lyrics = this.props.songs.map((song, index) =>
        <View style={styles.musicBox} key={index}>
        <View style={{width: 57, height: 59, borderRadius: 9, marginLeft: 15}}>
         <Image resizeMode="contain"
         style={{alignSelf: 'center', borderRadius: 9, width: 57, height: 59}}
          source={{uri: song[0].cover}}/>
          </View>
         <View style={styles.TextBox}>
          <Text 
          numberOfLines={1} 
          style={{fontFamily: 'nexaBold', fontSize: 20, color: 'white', flex: 1}}>
              {song[0].title}
          </Text>
          <View style={{flexDirection: 'row', }}>
          <Text 
          numberOfLines={1} 
          style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D', 
          marginRight: 5, }}>
              {song[0].author}
          </Text>
          <View style={{alignSelf:'center',width: 2, height: 2, borderRadius: 1, backgroundColor: '#917D7D',marginRight: 5}}>

          </View>
          <Text style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D'}}>
              {this.millisToMinutesAndSeconds(song.duration)}
          </Text></View>
         </View>
        </View>         
        );

        const music = 
            <ScrollView overScrollMode={'never'} keyboardShouldPersistTaps='always'>
            {lyrics}</ScrollView>;
        const shadowOpt = {
            color: "#000",
            border: 12,
            opacity: '0.08',
            radius: 12,
            x: 0,
            y: 1,
        };          
        return (
            <View style={{flex: 1}}>
            <View style={styles.linearGradient}>                                      
                {music}
                </View>
            </View>
        );
    }
}
import React,{Component}来自'React';
进口{
平台,
样式表,
文本,
形象,,
尺寸,
状态栏,
滚动视图,
看法
设备事件发射器,
平面列表,
活动指示器,
异步存储
}从“反应本机”;
从“/components/Splash”导入飞溅;
从“./components/Home”导入Home;
从“获取音乐文件”导入音乐文件;
从“反应本机权限”导入权限;
从'redux persist/integration/react'导入{PersistGate};
//从“/store/index”导入存储;
从“./store/index”导入索引;
常量{store,persistor}=index();
从'react redux'导入{connect,Provider};
导入{addSong,重置_操作
}来自“/actions/index”;
常量mapStateToProps=状态=>{
返回{
轨道:state.tracks
};
};
const mapDispatchToProps=调度=>{
返回{
addSong:song=>dispatch(addSong(song)),
复位动作
};
};
类reduxApp扩展组件{
毫秒和秒(毫秒){
var分钟=数学地板(毫/60000);
变量秒=((毫秒%60000)/1000).toFixed(0);
返回(秒==60?(分钟+1)+“:00”:分钟+”:“+(秒<10?:”)+秒);
}
componentDidMount(){
此.props.RESET_动作;
this.setState({loaded:false});
if(this.props.songs&&this.props.songs.length>0){
this.setState({loaded:true})
}否则{
这个。musicGetter();
}
}
musicGetter(){
权限。请求('存储')。然后(响应=>{
this.setState({photoPermission:response})
})
音乐档案({
id:是的,
模糊:错,
艺术家:是的,
持续时间:true,//默认值:true
cover:true,//默认值:true,
标题:对,
封面:对,
batchNumber:1,//每批获得5首歌曲
最小持续时间:10000,//以毫秒为单位,
字段:[“标题”、“艺术品”、“持续时间”、“艺术家”、“流派”、“歌词”、“专辑标题”]
})
}
组件willmount(){
/*DeviceEventEmitter.addListener(
“onBatchReceived”,
(参数)=>{
此.setState({歌曲:[
…这个州的歌,
…参数批处理
]},this.setState({loaded:true}));
}
);*/
DeviceEventEmitter.addListener(
“onBatchReceived”,
(参数)=>{
控制台日志(参数批处理);
this.props.addSong(params.batch);
this.setState({loaded:true});
}, 
);
}
async asynccer(){
试一试{
等待AsyncStorage.setItem('@MySuperStore:songs',JSON.stringify(this.state.songs));
}捕获(错误){
//保存数据时出错
}
}
建造师(道具){
超级(道具);
此.state={
时间流逝:错误,
照片许可证:“”,
歌曲:[],
是的,
加载:错误
};
}
render(){
如果(!this.state.loaded){
返回(
);
}否则{
返回(
);
}
}
}
函数connectWithStore(存储、WrappedComponent等参数){
var ConnectedWrappedComponent=connect(…args)(WrappedComponent)
返回功能(道具){
返回
}
}
const-App=连接存储(存储、reduxApp、mapStateToProps、mapDispatchToProps);
导出默认应用程序;
Home.js

import { createStore } from "redux";
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' 
import rootReducer from "../reducers/index";
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const persistConfig = {
    key: 'root',
    storage,
  //  stateReconciler: autoMergeLevel2,
    timeout: 0,
  }
const persistedReducer = persistReducer(persistConfig, rootReducer)
export default () => {
  let store = createStore(persistedReducer)
  let persistor = persistStore(store)
  return { store, persistor }
}    
export const addSong = song => ({type:
    "ADD_SONG", payload: song
});
export const RESET_ACTION = {
    type: "RESET"
}
import{ADD_SONG,RESET} from "../constants/action-types";
const initialState = {
    tracks: []
};
const rootReducer = (state = initialState, action) => {
    switch (action.type){
        case ADD_SONG:
        let index = state.tracks.findIndex(tracks => tracks.id == action.payload.id);    
        if(index != -1){
            return state;
        }else{
        return { 
            ...state,
            tracks: [...state.songs, action.payload]
        }
        }
        case RESET:
        return initialState;
        default:
            return state
    }
}
export default rootReducer;
import React, { Component } from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    Image,
    Dimensions,
    StatusBar,
    ScrollView,
    View,
    DeviceEventEmitter,
    FlatList,
    ActivityIndicator,
    AsyncStorage
} from 'react-native';
import Splash from './components/Splash';
import Home from './components/Home';
import MusicFiles from 'react-native-get-music-files';
import Permissions from 'react-native-permissions';
import { PersistGate } from 'redux-persist/integration/react';
//import store from "./store/index";
import index from './store/index';
const {store, persistor} = index();
import {connect, Provider} from 'react-redux';
import {addSong, RESET_ACTION
} from "./actions/index";

const mapStateToProps = state => {
    return {
        tracks: state.tracks
    };
};
const mapDispatchToProps = dispatch => {
    return {
      addSong: song => dispatch(addSong(song)),
      RESET_ACTION
    };
};

class reduxApp extends Component{
    millisToMinutesAndSeconds(millis) {
        var minutes = Math.floor(millis / 60000);
        var seconds = ((millis % 60000) / 1000).toFixed(0);
        return (seconds == 60 ? (minutes+1) + ":00" : minutes + ":" + (seconds < 10 ? "0" : "") + seconds);
      }
           componentDidMount() {
            this.props.RESET_ACTION;   
            this.setState({loaded: false});
            if(this.props.songs && this.props.songs.length > 0){
            this.setState({loaded: true})    
            }else{
            this.musicGetter();    
            }


           }
           musicGetter(){
            Permissions.request('storage').then(response => {
                this.setState({ photoPermission: response })
              })
              MusicFiles.getAll({
                  id : true,
                  blured : false,
                  artist : true,
                  duration : true, //default : true
                  cover : true, //default : true,
                  title : true,
                  cover : true,
                  batchNumber : 1, //get 5 songs per batch
                  minimumSongDuration : 10000, //in miliseconds,
                  fields : ['title','artwork','duration','artist','genre','lyrics','albumTitle']
                })
           }
           componentWillMount() {
        /*    DeviceEventEmitter.addListener(
                'onBatchReceived',
                (params) => {
                    this.setState({songs : [
                        ...this.state.songs,
                        ...params.batch
                    ]},this.setState({loaded: true}));
                }
            );*/
            DeviceEventEmitter.addListener(
                'onBatchReceived',
                (params) => {
                    console.log(params.batch);
                    this.props.addSong(params.batch);
                    this.setState({loaded: true});
                }, 
            );

        }
      async  asynccer(){

            try {
                await AsyncStorage.setItem('@MySuperStore:songs', JSON.stringify(this.state.songs));
              } catch (error) {
                // Error saving data
              }
        }
    constructor(props) {
        super(props);
        this.state = {
            timePassed: false,
            photoPermission: '',
            songs: [], 
            loaded: true,
            loading: false
        };
    }
  render() {
    if (!this.state.loaded) {
        return (
            <Splash/>
           );
    } else {
        return (
            <View style={styles.linearGradient}>
            <Provider store={store}>
            <PersistGate loading={null} persistor={persistor}>
            <Home songs={this.props.tracks}/>
            </PersistGate>
            </Provider>
            </View>
        );

    }
}
}
function connectWithStore(store, WrappedComponent, ...args) {
    var ConnectedWrappedComponent = connect(...args)(WrappedComponent)
    return function (props) {
      return <ConnectedWrappedComponent {...props} store={store} />
    }
  }
  const App = connectWithStore(store, reduxApp,mapStateToProps, mapDispatchToProps);
  export default App;
render() { 
        const lyrics = this.props.songs.map((song, index) =>
        <View style={styles.musicBox} key={index}>
        <View style={{width: 57, height: 59, borderRadius: 9, marginLeft: 15}}>
         <Image resizeMode="contain"
         style={{alignSelf: 'center', borderRadius: 9, width: 57, height: 59}}
          source={{uri: song[0].cover}}/>
          </View>
         <View style={styles.TextBox}>
          <Text 
          numberOfLines={1} 
          style={{fontFamily: 'nexaBold', fontSize: 20, color: 'white', flex: 1}}>
              {song[0].title}
          </Text>
          <View style={{flexDirection: 'row', }}>
          <Text 
          numberOfLines={1} 
          style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D', 
          marginRight: 5, }}>
              {song[0].author}
          </Text>
          <View style={{alignSelf:'center',width: 2, height: 2, borderRadius: 1, backgroundColor: '#917D7D',marginRight: 5}}>

          </View>
          <Text style={{fontFamily: 'nexaLight', fontSize: 10, color: '#917D7D'}}>
              {this.millisToMinutesAndSeconds(song.duration)}
          </Text></View>
         </View>
        </View>         
        );

        const music = 
            <ScrollView overScrollMode={'never'} keyboardShouldPersistTaps='always'>
            {lyrics}</ScrollView>;
        const shadowOpt = {
            color: "#000",
            border: 12,
            opacity: '0.08',
            radius: 12,
            x: 0,
            y: 1,
        };          
        return (
            <View style={{flex: 1}}>
            <View style={styles.linearGradient}>                                      
                {music}
                </View>
            </View>
        );
    }
}
render(){
const歌词=this.props.songs.map((歌曲,索引)=>
{歌曲[0]。标题}
{宋[0]。作者}
{this.millisToMinutesAndSeconds(song.duration)}
);
康斯特音乐=
{歌词};
常数shadowOpt={
颜色:“000”,
边界:12,
不透明度:“0.08”,
半径:12,
x:0,,
y:1,,
};          
返回(
{音乐}
);
}
}