【问题标题】:Fetching data from API in react native using redux使用redux从API中获取数据
【发布时间】:2018-01-10 00:03:22
【问题描述】:

我正在开发一个 react-native 项目,我正在尝试使用 axios 库从 api 获取数据并显示数据。所以,我的应用程序首先显示一个启动屏幕,然后它需要导航到一个页面,该页面包含选项卡。选项卡将包含来自 api 的数据。

所以,我正在尝试在初始屏幕之后的主页中初始化我的商店。我在 2 个不同的文件中分别定义了减速器和操作。

App.js 文件

import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation';
import SplashScreen from './src/components/SplashScreen';
import HomeScreen from './src/components/HomeScreen';

const Navigation = StackNavigator({
    Splash: {
      screen: SplashScreen
    },
    Home: {
      screen: HomeScreen
    }
})

export default Navigation;

我的 SplashScreen 组件:

import React from 'react';
import { StyleSheet,
         Text,
         View,
         } from 'react-native';

export default class SplashScreen extends React.Component {
  static navigationOptions = {
    header: null
  }

  componentWillMount() {
    setTimeout(() => {
      this.props.navigation.navigate('Home')
    },2000)
  }

  render() {
    return(
        <View style={styles.container}>
          <Text style={styles.welcome}>Splash Screen</Text>
        </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'skyblue'
  },
  welcome: {
    color: '#FFF',
    fontSize: 30
  }
})

我的主屏幕组件:

import React from 'react';
import { StyleSheet,
         Text,
         View,
         } from 'react-native';

export default class SplashScreen extends React.Component {
  static navigationOptions = {
    header: null
  }

  componentWillMount() {
    setTimeout(() => {
      this.props.navigation.navigate('Home')
    },2000)
  }

  render() {
    return(
        <View style={styles.container}>
          <Text style={styles.welcome}>Splash Screen</Text>
        </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'skyblue'
  },
  welcome: {
    color: '#FFF',
    fontSize: 30
  }
})




import React from 'react';
import { StyleSheet,
         Text,
         View,
         } from 'react-native';

export default class SplashScreen extends React.Component {
  static navigationOptions = {
    header: null
  }

  componentWillMount() {
    setTimeout(() => {
      this.props.navigation.navigate('Home')
    },2000)
  }

  render() {
    return(
        <View style={styles.container}>
          <Text style={styles.welcome}>Splash Screen</Text>
        </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'skyblue'
  },
  welcome: {
    color: '#FFF',
    fontSize: 30
  }
})

Action.js 文件

import axios from 'axios';
export const FETCH_DATA = 'fetch_data';

const API = 'https://api.myjson.com/bins/fz62x';

export function fetchData() {
  const request = axios.get(API);

  return dispatch => {
    return request.then((data) => {
        dispatch({
          type: FETCH_DATA,
          payload: data
        })
    })
  }
}

我的减速机

import { FETCH_DATA } from './actions';

export default function(state={}, action) {
  switch(action.type) {
    case FETCH_DATA:
      return {
        ...state,
        action.payload
      };

    default:
        return state;
  }
}

谁能告诉我这是否正确?如果不是,那么正确的方法是什么?

【问题讨论】:

    标签: react-native redux


    【解决方案1】:

    我想说没有正确或不正确的方法可以做到这一点。但我可以分享一种我通常使用的模式。

    首先,我会为不同的文件创建单独的文件夹。 Actions 文件夹中的 Actions,reducers 文件夹中的 reducers 等...我将创建单独的 constants.js 文件和 configureStore.js 文件并将它们放在项目根目录中。

    我会放弃 Axios 库,只使用 Fetch API 来获取数据。考虑到您的代码,我将执行以下操作。

    在您的项目root 目录中创建configureStore.js 文件。我建议你使用Redux-Thunk。你可以从here找到更多信息。

    configureStore.js

    import { createStore, applyMiddleware } from 'redux';
    import app from './reducers';
    import thunk from 'redux-thunk';
    
    export default function configureStore() {
        let store = createStore(app, applyMiddleware(thunk))
        return store
    }
    

    App.js

    import React, { Component } from 'react';
    import { Provider } from 'react-redux';
    import { StackNavigator } from 'react-navigation';
    import configureStore from './configureStore';
    import HomeScreen from './screens/HomeScreen';
    
    const NavigationApp = StackNavigator({
        HomeScreen: { screen: HomeScreen }
    })
    
    const store = configureStore()
    
    export default class App extends Component {
    
        render() {
            return (
                <Provider store={store}>
                    <NavigationApp />
                </Provider>
            );
        }
    }
    

    让我们创建constants.js 并将其放在项目root 目录中。

    constants.js

    export const FETCHING_TODOS = 'FETCHING_TODOS';
    export const FETCH_TODOS_SUCCESS = 'FETCH_TODOS_SUCCESS';
    export const FETCH_TODOS_FAILURE = 'FETCH_TODOS_FAILURE';
    

    现在让我们继续创建我们的操作文件,该文件将放在actions 文件夹中。让我们将其命名为 fetchToDos.js。让我们使用Fetch API 创建一个简单的函数。

    fetchToDos.js

    import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
    
    export function fetchToDos() {
    
        return (dispatch) => {
            dispatch(getTodos())
    
            return(fetch('https://api.myjson.com/bins/fz62x'))
            .then(res => res.json())
            .then(json => {
    
                return(dispatch(getToDosSuccess(json)))
            })
            .catch(err => dispatch(getToDosFailure(err)))
        }
    }
    
    function getToDos() {
    
        return {
            type: FETCHING_TODOS
        }
    }
    
    function getToDosSuccess(data) {
    
        return {
            type: FETCH_TODOS_SUCCESS,
            data
        }
    }
    
    function getToDosFailure() {
        return {
            type: FETCH_TODOS_FAILURE
        }
    }
    

    fetchToDos.js 与 Axios

    import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
    import axios from 'axios';
    
    export function fetchToDos() {
    
        return (dispatch) => {
            dispatch(getUser())
            axios.get('https://api.myjson.com/bins/fz62x')
                .then(function (response) {
    
                    // handle your response here, create an object/array/array of objects etc... 
                    // and return it in dispatch(getToDosSuccess(data over here))
    
                    return(dispatch(getToDosSuccess(response.data)))
                })
                .catch(err => dispatch(getToDosFailure(err)))
        }
    }
    
    // rest is the same...
    

    继续使用减速器。让我们创建两个文件 - index.jstodos.js 并将它们放在 reducers 文件夹中。

    todos.js

    import { FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE, FETCHING_TODOS } from '../constants';
    
    const initialState = {
        todos: [],
        isFetching: false,
        error: false
    }
    
    export default function todosReducer(state = initialState, action) {
    
        switch(action.type) {
            case FETCHING_TODOS:
                return {
                    ...state,
                    isFetching: true
                }
            case FETCH_TODOS_SUCCESS:
                return {
                    ...state,
                    isFetching: false,
                    todos: action.data
                }
            case FETCH_TODOS_FAILURE:
                return {
                    ...state,
                    isFetching: false,
                    error: true
                }
            default:
                return state
        }
    }
    

    index.js

    import { combineReducers } from 'redux';
    import todos from './todos';
    
    const rootReducer = combineReducers({
        todos
    })
    
    export default rootReducer
    

    基本上“繁重的工作”已经完成。我只会创建一个屏幕,因为让我们假设用户在主屏幕上点击返回按钮(Android),他们最终会出现在那个启动屏幕上。所以在这个例子中,我将只使用一个屏幕。

    HomeScreen.js

    import React, { Component } from 'react';
    import {
        View,
        Text,
        ActivityIndicator
    } from 'react-native';
    import { bindActionCreators } from 'redux';
    import { connect } from 'react-redux';
    import { fetchTodos } from '../actions/fetchTodos';
    
    class HomeScreen extends Component {
    
        componentDidMount() {
    
            this.props.fetchTodos()
    
        }
    
        render() {
    
            const { todos, isFetching } = this.props.todos
    
            if (isFetching) {
                return(
                    <View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
                        <ActivityIndicator size={'large'} /> 
                    </View>
                )
            } else {
                return(
                    <View style={{flex: 1, flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
                        <Text>todos.length</Text>
                    </View>
                )
            }
    
        }
    
    }
    
    function mapStateToProps(state) {
        return {
            todos: state.todos
        }
    }
    
    function mapDispatchToProps(dispatch) {
        return {
            ...bindActionCreators({ fetchTodos }, dispatch)
        }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen)
    

    我真的希望这个概念对你有用,因为根据我的经验,我可以说它在我刚开始的时候帮助了我很多,它帮助我更好地理解了 redux 的整个概念。

    抱歉,如果有任何错别字和错误。我很忙。

    【讨论】:

    • 如果你不介意,我可以问你一个问题。所以,如果我想使用 axios 来获取数据,那么需要进行哪些更改。实际上,我有点困惑你提到的动作的 fetchToDo.js 文件。我的意思是,我只是想简单地使用 axios 库从 api 获取结果。对不起,我对 redux 很陌生,所以这让我很困惑。如果你不介意,你能告诉我如何用 axios 库编写一个简单的动作文件,它只会从 api 获取数据吗?
    • @pranami 我使用 Axios 创建了一个数据获取方法,它与 Fetch API 非常非常相似。
    • 在我不希望数据保存在存储中的情况下,您是否建议我们可以避免这种“从屏幕调度到服务,然后在减速器中完成工作”路径?跨度>
    • @Neo 是的,绝对。任何适合您的需求。
    • 请任何人都可以告诉我如何将参数传递给fetchTodos 操作?
    猜你喜欢
    • 1970-01-01
    • 2021-09-27
    • 1970-01-01
    • 2022-06-15
    • 2020-11-04
    • 2021-02-06
    • 1970-01-01
    • 1970-01-01
    • 2019-03-15
    相关资源
    最近更新 更多