native react 笔记_react native 指定react-native版本 - CSDN
  • ReactNative学习笔记

    2019-04-01 21:52:54
    ES6声明变量的6中方法 var function let const import class onChangeText={()=>this.update(nextText)}语句可以写成 onChangeText={this.update} 不可以写成onChangeText={this.update(nextText)} ...

    ES6声明变量的6中方法
    var function let const import class

    onChangeText={()=>this.update(nextText)}语句可以写成
    onChangeText={this.update}
    不可以写成onChangeText={this.update(nextText)}

    在RN开发中,开发者需要将状态机变量视为"不可变的常量"
    永远不要出现"this.state.某状态机变量名=某值"
    在RN中当开发者需要改变状态机量的值时,一定要并且只能使用this.setState函数

    在不影响程序结构的情况下,尽可能减少有状态的RN组件的数目.
    有状态指的是有了状态机变量
    对于无状态的RN组件来说,会被改变的数据来源于它的props(属性);有状态的RN组件来说,不仅来自于它的props,还来自于它的state(状态机变量)

    必须要有状态机变量的情况:
    不可预知的输入性事件(用户输入,文本输入,麦克输入,处理网络数据,定时器等),需要对应的状态机变量.

    遵守两个RN开发准则:
    (1)只使用setState函数来改变状态机变量!
    (2)尽一切可能让UI中可变的数据来源是状态机变量与属性!

    ES6不仅支持给一个对象动态增加成员变量,而且也支持动态删除一个对象的成员变量.replaceState正是使用的动态删除对象的成员变量来实现的.

    强制启动渲染forceUpdate 尽可能的少用此函数.

    组件的成员变量以下画线明确的提醒开发者这是一个组件的成员变量.

    module.exports=组件名 表示该组件已经准备好供外部其他模块使用.

    TextInput组件在Android平台上可以不设置组件高度.

    不同平台执行代码,通过Platform API来进行判断.

    let Platform=require(‘Platform’);
    let (Platform.OS===“android”){
    …/Android平台需要运行的代码
    }else{
    …//IOS平台需要运行的代码
    }

    展开全文
  • React Native 学习笔记

    2016-11-01 16:59:08
    ReactNative学习笔记,基于一个经典教程,附适配0.36版本源代码

    教程的原文链接:https://www.raywenderlich.com/126063/react-native-tutorial

    中文链接:http://www.kancloud.cn/digest/reactvavtive/75166

    由于RN更新的缘故,于是对源代码进行了适配,基于目前的0.36版本

    GitHub地址:https://github.com/marvincreat/React-Native-PropertyFinderNewDemo


    React Native - PropertyFinderDemo学习笔记

    PART1:综述

    1. 关于代码整体结构

    第一块是加载 react-native 模块及所需要的原生组件如image组件,以及引入其他js文件的组件
    //加载各种原生组件
    import React, { Component } from 'react';
    import {
        AppRegistry,
        StyleSheet,
        Text,
        View,
        NavigatorIOS
    } from 'react-native';
    
    //引入其他JS组件
    import SearchPage from './SearchPage';

    写法比较固定,如果用到的原生组件未引入,会报错。

    第二块布局样式
    var styles = StyleSheet.create({
        thumb: {
            width:80,
            height:80,
            marginRight:10
        },
        textContainer: {
            flex: 1
        },
        separator: {
            height: 1,
            backgroundColor: '#dddddd'
        },
        price:{
            fontSize: 25,
            fontWeight: 'bold',
            color: '#48BBEC'
        },
        title: {
            fontSize: 20,
            color: '#48BBEC'
        },
        rowContainer: {
            flexDirection: 'row',
            padding: 10
        }
    });
    
    第三块自定义组件部分,包括可以被其他js文件引用的组件,组件里面有属性声明,自定义方法,以及渲染界面等
    //自定义新组件
    function urlForQueryAndPage(key, value, pageNumber) {
        var data = {
            country: 'uk',
            pretty: '1',
            encoding: 'json',
            listing_type: 'buy',
            action: 'search_listings',
            page: pageNumber
        };
        data[key] = value;
    
        var querystring = Object.keys(data).map(key => key + '=' + encodeURIComponent(data[key])).join('&');
        console.log(querystring);
        return 'http://api.nestoria.co.uk/api?' + querystring;
    };
    
    //可供外部访问的组件定义方法
    export default class SearchPage extends Component {
        constructor(props) {
            super(props);
            this.state = {
                searchString: 'london',
                isLoading: false,
                message: ''
            }
        };
    
        onSearchTextChanged(text) {
            console.log('onSearchTextChanged');
            this.setState({searchString: text})
            console.log(this.state.searchString);
        };
    
        _executeQuery(query) {
            console.log(query);
            this.setState({
                isLoading: true
            });
            fetch(query)
            .then(response => response.json())
            .then(json => this._handleResponse(json.response))
            .catch(error =>
                this.setState({
                    isLoading: false,
                    message: 'Something bad happend ' + error
                })
            );
        };
    
        _handleResponse(response) {
            this.setState({ isLoading: false , message: '' });
            if (response.application_response_code.substr(0, 1) === '1') {
                //console.log('Properties found: ' + response.listings.length);
                this.props.navigator.push({
                    title: 'Results',
                    component: SearchResults,
                    passProps: {listings: response.listings} //passProps中传递的属性
                });
            } else {
                this.setState({ message: 'Location not recognized; please try again.'});
            }
        }
    
    
        onSearchPressed() {
            var query = urlForQueryAndPage('place_name', this.state.searchString, 1);
            this._executeQuery(query);
        };
    
        render() {
            console.log('SearchPage.render');
            var spinner = this.state.isLoading ?
                ( <ActivityIndicator size='large'/>) :
                ( <View/>)
            return (
                <View style={styles.container}>
                    <Text style={styles.description}>
                        Search for houses to buy!
                    </Text>
                    <Text style={styles.description}>
                        Search by place-name, postcode or search near your location.
                    </Text>
                    <View style={styles.flowRight}>
                        <TextInput
                            style={styles.searchInput}
                            value={this.state.searchString}
                            onChangeText={(text) => this.onSearchTextChanged(text)}
                            placeholder='Search via name or postcode'>
                        </TextInput>
                        <TouchableHighlight
                            style={styles.button}
                            underlayColor='#99D9F4'
                            onPress={this.onSearchPressed.bind(this)}>
                            <Text style={styles.buttonText}>Go</Text>
                        </TouchableHighlight>
                    </View>
                    <TouchableHighlight
                        style={styles.button}
                        underlayColor='#99D9F4'>
                        <Text style={styles.buttonText}>Location</Text>
                    </TouchableHighlight>
                    <Image
                        source={ require('./Resources/house.png')}
                        style={styles.image}
                    />
                    <Text style={styles.description}>{this.state.message}</Text>
                    {spinner}
    
    
                </View>
            );
        }
    }
    
    //module .exports = SearchPage;//另一种写法,供外部访问
    

    最后是AppRegistry,用来告知React Native哪一个组件被注册为整个应用的根容器。一般在整个应用里AppRegistry.registerComponent这个方法只会调用一次。

    AppRegistry.registerComponent('PropertyFinder', () => PropertyFinderApp);
    

    2. 关于布局

    与css3类似等布局,而flex部分主要是

    • flexDirection(决定主轴是水平row还是垂直column)
    • justifyContent(子元素沿着主轴的排列方式,flex-start、center、flex-end、space-around以及space-between)
    • alignItems(子元素沿着垂直与主轴的次轴的排列方式,lex-start、center、flex-end以及stretch)
    • flexWrap (是否支持弹性nowrap | wrap | wrap-reverse)

    3. 关于网络请求

    由于之前未接触过fetch api,基本过程如下,需要进一步熟悉和研究

    //将请求参数生成url进行请求
    function urlForQueryAndPage(key, value, pageNumber) {
        var data = {
            country: 'uk',
            pretty: '1',
            encoding: 'json',
            listing_type: 'buy',
            action: 'search_listings',
            page: pageNumber
        };
        data[key] = value;
    
        var querystring = Object.keys(data).map(key => key + '=' + encodeURIComponent(data[key])).join('&');
        console.log(querystring);
        return 'http://api.nestoria.co.uk/api?' + querystring;
    };
    
    //执行请求
        _executeQuery(query) {
            console.log(query);
            this.setState({
                isLoading: true
            });
            fetch(query)
            .then(response => response.json())
            .then(json => this._handleResponse(json.response))
            .catch(error =>
                this.setState({
                    isLoading: false,
                    message: 'Something bad happend ' + error
                })
            );
        };
    
        //请求结果判断
        _handleResponse(response) {
            this.setState({ isLoading: false , message: '' });
            if (response.application_response_code.substr(0, 1) === '1') {
                //console.log('Properties found: ' + response.listings.length);
                this.props.navigator.push({
                    title: 'Results',
                    component: SearchResults,
                    passProps: {listings: response.listings} //passProps中传递的属性
                });
            } else {
                this.setState({ message: 'Location not recognized; please try again.'});
            }
        }
    
    
        //请求传递参数
        onSearchPressed() {
            var query = urlForQueryAndPage('place_name', this.state.searchString, 1);
            this._executeQuery(query);
        };

    4. 关于导航

    在进一步研究中

    initialRoute
    它定义了Navigator的初始化组件,该组件将在应用启动时加载。

    configureScene
    配置界面与界面之间跳转时的动画效果

    renderScene
    渲染对应的组件

    passProps传参等

    this.props.navigator.push({
                    title: 'Results',//push目标页导航title
                    component: SearchResults,//push目标
                    passProps: {listings: response.listings} 
                    //passProps中传递的属性
                });

    PART 2 实现过程 架构设计分析

    主要构成文件是:index.ios.js(注册APP根容器组件)/SearchPage.js(根容器组件对应的View)/SearchResults.js(搜索结果列表View)/PropertyView.js(搜索结果详情页View)

    ==index.ios.js==

    含有一个名为PropertyFinder的自定义组件,类似rootview,

    class PropertyFinderApp extends Component {
        render() {
            return (
                <NavigatorIOS
                    style = {styles.container}
                    initialRoute = {{
                    title: 'Property Finder',
                    component: SearchPage,
                    }} />
            )
        }
    }

    将该组件注册为APP的根容器,

    AppRegistry.registerComponent('PropertyFinder', () => PropertyFinderApp);
    

    并引入另一个名为SearchPage.js文件,

    import SearchPage from './SearchPage';
    

    调用其中的SearchPage组件作为根容器的视图,

                <NavigatorIOS
                    style = {styles.container}
                    initialRoute = {{
                    title: 'Property Finder',
                    component: SearchPage,
                    }} />
    

    注意NavigatorIOS它是基于UINavigationController封装的仅供iOS使用,如果要兼容Android,可以使用纯JavaScript实现的导航栈Navigator,参考下面两个文章

    导航对比:
    https://github.com/reactnativecn/react-native-docs-cn/blob/master/docs/0.31/navigation.md

    Navigator介绍:
    http://bbs.reactnative.cn/topic/20/%E6%96%B0%E6%89%8B%E7%90%86%E8%A7%A3navigator%E7%9A%84%E6%95%99%E7%A8%8B

    ==SearchPage.js==

    该文件包含一个SearchPage的组件供外部引用:

    export default class SearchPage extends Component {...}
    

    包括几部分:

    构造函数,每个React组件都有一个state对象,它是一个键值存储对象。在组件被渲染之前,我们可以设置组件的state对象。(类似iOS的属性声明),声明了搜索关键字,加载动画状态,以及提示信息。

        constructor(props) {
            super(props);
            this.state = {
                searchString: 'london',
                isLoading: false,
                message: ''
            }
        };

    渲染界面,用于首页view的界面布局

        render() {
            console.log('SearchPage.render');
            var spinner = this.state.isLoading ?
                ( <ActivityIndicator size='large'/>) :
                ( <View/>)
            return (
                <View style={styles.container}>
                    <Text style={styles.description}>
                        Search for houses to buy!
                    </Text>
                    <Text style={styles.description}>
                        Search by place-name, postcode or search near your location.
                    </Text>
                    <View style={styles.flowRight}>
                        <TextInput
                            style={styles.searchInput}
                            value={this.state.searchString}
                            onChangeText={(text) => this.onSearchTextChanged(text)}
                            placeholder='Search via name or postcode'>
                        </TextInput>
                        <TouchableHighlight
                            style={styles.button}
                            underlayColor='#99D9F4'
                            onPress={this.onSearchPressed.bind(this)}>
                        <Text style={styles.buttonText}>Go</Text>
                    </TouchableHighlight>
                    </View>
                    <TouchableHighlight
                        style={styles.button}
                        underlayColor='#99D9F4'
                        onPress = {this.onLocationPressed.bind(this)}>
                        <Text style={styles.buttonText}>Location</Text>
                    </TouchableHighlight>
                    <Image
                        source={ require('./Resources/house.png')}
                        style={styles.image}
                    />
                    <Text style={styles.description}>{this.state.message}</Text>
                    {spinner}
    
    
                </View>
            );
        }
    }

    网络请求方法,包括执行、请求结果处理

        //执行请求
        _executeQuery(query) {
            console.log(query);
            this.setState({
                isLoading: true
            });
            fetch(query)
            .then(response => response.json())
            .then(json => this._handleResponse(json.response))
            .catch(error =>
                this.setState({
                    isLoading: false,
                    message: 'Something bad happend ' + error
                })
            );
        };
    
        //请求结果
        _handleResponse(response) {
            this.setState({ isLoading: false , message: '' });
            if (response.application_response_code.substr(0, 1) === '1') {
                //console.log('Properties found: ' + response.listings.length);
                this.props.navigator.push({
                    title: 'Results',
                    component: SearchResults,
                    passProps: {listings: response.listings} //passProps中传递的属性
                });
            } else {
                this.setState({ message: 'Location not recognized; please try again.'});
            }
        };

    事件方法,触发请求方法

       onSearchTextChanged(text) {
            //console.log('onSearchTextChanged');
            this.setState({searchString: text})
            //console.log(this.state.searchString);
        };
        //搜索事件请求
        onSearchPressed() {
            var query = urlForQueryAndPage('place_name', this.state.searchString, 1);
            this._executeQuery(query);
        };
    
        //定位事件请求
        onLocationPressed() {
            //获取当前位置
            navigator.geolocation.getCurrentPosition(
                location => {
                    var search = location.coords.latitude + ',' + location.coords.longitude;
                    this.setState( { searchString: search } );
                    var query = urlForQueryAndPage('centre_point', search, 1);
                    this._executeQuery(query);
                },
                error => {
                    this.setState( {
                        message: 'There was a problem with obtaining your location: ' + error
                    });
                }
            );
        }

    navigator.geolocation可获取当前位置,如果当前位置获取成功,我们将调用第一个箭头函数,否则调用第二个箭头函数简单显示一下错误信息。

    如果未开启定位APP集成RN,需要在Info.plist中增加NSLocationWhenInUseUsageDescription字段来启用定位功能。如果使用react-native init创建项目,定位会被默认启用。

    类外部函数,处理请求URL

    //自定义函数
    function urlForQueryAndPage(key, value, pageNumber) {
        var data = {
            country: 'uk',
            pretty: '1',
            encoding: 'json',
            listing_type: 'buy',
            action: 'search_listings',
            page: pageNumber
        };
        data[key] = value;
    
        var querystring = Object.keys(data).map(key => key + '=' + encodeURIComponent(data[key])).join('&');
        console.log('querystring: ' + querystring);
    
        return 'http://api.nestoria.co.uk/api?' + querystring;
    };

    ==SearchResults.js==

    该文件定义了一个组件供外部的SearchPage组件使用,用于展示搜索结果列表,侧重于listView的使用。

    export default class SearchResults extends Component {...}

    分为三部分

    构造函数用于定义属性,构建listView的数据源,构建数据源的时候,使用箭头函数对不同的row进行识别。这个函数在ListView进行“一致化”的时候被调用,以便判断列表中的数据是否被改变。Nestoria API有一个guid全局唯一标识符属性,刚好可以用来作为判断的标准。

        constructor(props) {
            super(props);
            //console.log('this.props.listings' + this.props.listings);
    
            var dataSource = new ListView.DataSource(
                {rowHasChanged: (r1, r2) => r1.guid !== r2.guid});
            this.state = {
                dataSource: dataSource.cloneWithRows(this.props.listings)
            };
        }
    

    这里的this.props.listings,就是从上个页面请求到数据以后通过navigatorIOS传过来的

                this.props.navigator.push({
                    title: 'Results',
                    component: SearchResults,
                    passProps: {listings: response.listings} //passProps中传递的属性
    

    ListView组件必须的两个属性是dataSource和renderRow。dataSource是列表的数据源,而renderRow则逐个解析数据源中的数据,然后返回一个设定好格式的组件来渲染。

    rowHasChanged函数也是ListView的必需属性。这里只是简单的比较两行数据是否是同一个数据(===符号只比较基本类型数据的值,和引用类型的地址)来判断某行数据是否变化了。

    renderRow函数则用于为每个行提供UI

        renderRow(rowData, sectionID, rowID) {
            var price = rowData.price_formatted.split(' ')[0];
            console.log('rowData.price' + price);//rowData.price_formatted可以加上价格符号
    
            return (
                <TouchableHighlight onPress = {() => this.rowPressed(rowData.guid)}
                    underlayColor='#dddddd'>
                    <View>
                        <View style = {styles.rowContainer}>
                            <Image style = {styles.thumb} source = {{ uri: rowData.img_url }} />
                            <View style = {styles.textContainer}>
                                <Text style = {styles.price}>
                                    {price}
                                </Text>
                                <Text style = {styles.title}
                                    numberOfLines={1}>{rowData.title}
                                </Text>
                            </View>
                        </View>
                        <View style = {styles.separator} />
                    </View>
                </TouchableHighlight>
            );
        }
    

    rowPressed函数执行行点击事件,并传递详情页参数

        rowPressed(propertyGuid) {
            var property = this.props.listings.filter(prop => prop.guid === propertyGuid)[0];
    
            this.props.navigator.push({
                title: "Property",
                component: PropertyView,
                passProps: {property: property}
            });
        }

    渲染部分,创建listView

    render() {
            return (
                <ListView
                    dataSource = {this.state.dataSource}
                    renderRow = {this.renderRow.bind(this)}/>
            )
        }

    ==PropertyView.js==

    这个文件比较简单,渲染一个上面是图片,下面是文字的详情页,引入SearchResults组件里的rowPressed函数传递的参数

        rowPressed(propertyGuid) {
            var property = this.props.listings.filter(prop => prop.guid === propertyGuid)[0];
    
            this.props.navigator.push({
                title: "Property",
                component: PropertyView,
                passProps: {property: property}
            });
        }
    

    创建组件,渲染函数

    “`
    export default class PropertyView extends Component {
    render() {
    var property = this.props.property;
    var stats = property.bedroom_number + ’ bed ’ + property.property_type;
    if (property.bathroom_number) {
    stats += ’ . ’ + property.bathroom_number + ’ ’ + (property.bathroom_number > 1 ? ‘bathrooms’ : ‘bathroom’);
    }

        var price = property.price_formatted.split(' ')[0];
    
        return (
            <View style={styles.container}>
                <Image style={styles.image}
                       source={{uri: property.img_url}}/>
                <View style={styles.heading}>
                    <Text style={styles.price}> {price} </Text>
                    <Text style={styles.title}> {property.title} </Text>
                    <View style={styles.separator}/>
                </View>
                <Text style={styles.description}> {stats} </Text>
                <Text style={styles.description}> {property.summary}</Text>
            </View>
        )
    }
    

    }

    展开全文
  • React Native学习笔记

    2018-07-16 10:44:52
    1. react-native init AwesomeProject解决方案:react-native 0.55.6版本的问题,需要在init项目的时候指定老版本号,比如0.55.4 react-native init AwesomeProject -- version 0.55.42. react-native run-android...

    1. react-native init AwesomeProject

    原因分析:react-native 0.55.6版本的问题,需要在init项目的时候指定老版本号,比如0.55.4

    解决方案:react-native init AwesomeProject -- version 0.55.4

    2. react-native run-android 

    Execution failed for task ‘:app:prepareSrolkReactNativeFilePickerUnspecifiedLibrary'.

    Could not expand ZIP ...node_modules\react-native-file-picker\android\build\outputs\aar\react-native-file-picker-release.aar

    解决方案:cd android>gradlew clean>cd..>react-native run-android

    3. 直接用AS运行react-native项目报错


    原因分析:直接运行,在android/app/src/main/assets目录下面是没有bundle文件的



    展开全文
  • 效果图典型的tab导航应用界面路由使用的是react-native-router-flux(简称rnrf),基于react-navigation,这两者目前还都不稳定rnrf中主要的概念有:Router、Scene、Actions等,具体内容可以去官网了解react-redux...

    效果图

    典型的tab导航应用

    界面路由

    使用的是react-native-router-flux(简称rnrf),基于react-navigation,这两者目前还都不稳定

    rnrf中主要的概念有:Router、Scene、Actions等,具体内容可以去官网了解

    react-redux结合rnrf的使用
    redux中的Store只有一个,且应该定义在应用最上层

    rnrf中的Router本质是component,是所有界面的顶层视图

    那么Store应该从Router开始向下传递

    上代码

    const createStoreWithMiddleware = applyMiddleware(thunk)(createStore)
    const store = createStoreWithMiddleware(allReducers)
    const styles = StyleSheet.create({
        navigationBar: {
            backgroundColor: yellow_EF7907
        },
        title: {
            color: 'white'
        },
        tabbarContainer: {
            backgroundColor: "#f6f6f6",
        }
    })
    
    //应用中需要使用的页面都在这里声明
    export default class DemoApp extends BasePureComponent {
        render() {
            return (
                <Provider store={store}>
                    <Router createReducer={reducerCreate}>
                        <Scene key="root">
                            <Scene
                                key="tabbar"
                                tabs={true} //使用TabNavigator导航
                                tabBarPosition="bottom" //tab的位置
                                tabBarStyle={styles.tabbarContainer}  //底部tab样式
                                showLabel={false} //是否显示底部tab的文字
                                lazy={true} //每个tab的页面是否懒加载
                                swipeEnabled={true} //是否允许滑动切换tab
    
                                // navigationBarStyle={styles.navigationBar} //顶部标题栏样式
                                // titleStyle={styles.title} //顶部标题样式
                                navBar={NavBar}
                            >
    
                                <Scene icon={TabIcon} key={SCENE_HOME.key} component={HomeProvider}
                                       title={SCENE_HOME.title}/>
                                <Scene icon={TabIcon} key={SCENE_CLASSIFY.key} component={ClassifyPage}
                                       title={SCENE_CLASSIFY.title}/>
    
                                <Scene icon={TabIcon} key={SCENE_FOLLOW.key} component={FollowPage}
                                       title={SCENE_FOLLOW.title}/>
    
                                <Scene icon={TabIcon} key={SCENE_YUBA.key} component={YubaPage} title={SCENE_YUBA.title}/>
                                <Scene icon={TabIcon} key={SCENE_ME.key} component={MeProvider} title={SCENE_ME.title}/>
                            </Scene>
                        </Scene>
                    </Router>
                </Provider>
            )
        }
    
        componentDidMount() {
            printf('store', store)
            printf('state', store.getState())
        }
    }
    react-redux使用Provider组件传递store,从Provider源码可以略知一二

    export function createProvider() {
      var _Provider$childContex;
    
      var storeKey = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'store';

    redux应用结构

    既然使用了redux,就得按照redux要求的方式写代码,工程目录结构也得顺应潮流



    实践示例

    下面的步骤都是以首页为例

    创建组件
    组件化的首页代码十分清爽,如下

    class HomePage extends BasePureComponent {
        render() {
            this.logMsg('render')
            this.logMsgWithKey('props', this.props)
            return (
                <ScrollView style={styles.container}>
                    <BannerProvider/>
                    <ClassifyProvider/>
                    <RecoListProvider/>
                </ScrollView>
            )
        }
    
        componentDidMount() {
            let param = {
                from: 'home-index'
            }
            this.props.refreshHomePage(param)
        }
    }
    声明组件的action
    组件中存在哪些事件,将他们用action表示出来

    首页需要一个刷新事件,就按如下定义

    export const REFRESH_HOMEPAGE = 'refreshHomePage' //刷新首页
    const refreshHomePageAction = (data = {}) => {
        return {
            type: REFRESH_HOMEPAGE,
            data
        }
    }
    
    export const refreshHomePage = (dispatch, param) => {
        refreshHomePageTask(dispatch, param, refreshHomePageAction)
    }
    refreshHomePageAction就表示刷新事件的action,这个action携带一个数据data

    data有什么用呢?

    refreshHomePage这个方法什么时候执行呢?

    dispatch这个参数是什么?param又从哪里来?

    refreshHomePageTask又是什么鬼?

    好吧,带着这些问题继续往下看

    声明action对应的task
    从refreshHomePageAction的定义可以看到,我们并不想这个action立即被dispatch,而是将它交给了refreshHomePageTask

    赶紧看看refreshHomePageTask是什么

    export const refreshHomePageTask = (dispatch, param = {}, action) => {
        printf('refreshHomePageTask' + '_请求参数:', param)
        return new Promise((resolve, reject) => {
            resolve(initHomeData())
        }).then((res) => {
            printf('refreshHomePageTask' + '_请求结果:', res)
            dispatch(action(res))
        })
    }
    initHomeData = () => {
        return {
            status: 200,
            serverTime: new Date().valueOf()
        }
    }
    refreshHomePageTask接收三个参数

    dispatch:分发器(暂时这么理解,可以肯定地告诉你,它来自store,而且是个函数
    param:请求参数(可以认为是传给task的参数)
    action:需要分发的事件(这里实际接收的就是refreshHomePageAction)

    在执行完Promise容器中的内容后,将结果交给refreshHomePageAction

    再回顾一下refreshHomePageAction的模样,它返回的是一个普通对象(可以理解成final action),task执行的结果最终变成这个普通对象的一部分

    const refreshHomePageAction = (data = {}) => {
        return {
            type: REFRESH_HOMEPAGE,
            data
        }
    }
    最后执行dispatch方法,将这个final action分发出去,接下来就会执行reducer

    声明组件的reducer
    上代码

    export const homeIndex = (state = initHomeData(), action) => {
        printf('homeIndex Reducer receive an action:', action)
        switch (action.type) {
            case REFRESH_HOMEPAGE:
                return action.data
            default:
                return state
        }
    }
    initHomeData = () => {
        return {
            status: 200,
            serverTime: new Date().valueOf()
        }
    }
    homeIndex方法接收state和action两个参数,state可以有初始值

    redux是怎么会执行homeIndex这个方法的呢?
    还记得在界面路由创建的store时传入的reducer吗?再贴一遍代码。

    const createStoreWithMiddleware = applyMiddleware(thunk)(createStore)
    const store = createStoreWithMiddleware(allReducers)
    因为reducer按应用模块划分,所以每个模块的reducer都放在了allReducers中,看到homeIndex了吗?

    //所有的reducer
    export const allReducers = combineReducers({
        homeIndex,
        homeBanner,
        homeClassify,
        homeRecolist,
        meIndex
    });
    正是因为创建store时,reducer是作为参数传入的,那么redux在dispatch一个action之后,redux当然知道要执行哪些reducer了(事实上传入的每个reducer都会被执行,最后会通过log验证这个事实)


    绑定组件
    主要就是mapXXXToProps那两个方法

    上代码

    //state中包括了所有绑定组件的state,return的是当前组件需要放在props中的数据
    mapStateToProps = (state) => {
        return state.homeIndex
    }
    
    //return 的是组件中需要放在props中的方法
    mapDispatchToProps = (dispatch) => {
        return {
            refreshHomePage: (param) => refreshHomePage(dispatch, param)
        }
    }
    
    //绑定组件
    export default connect(
        mapStateToProps,
        mapDispatchToProps
    )(HomePage)
    mapStateToProps中返回的就是组件需要的数据(从store的state中取的),最终这些数据会变成组件props的一部分

    比如 state.homeIndex被某个reducer改成如下

     {
         status: 200,
         serverTime: 1314
     }
    组件的props被更新后,就可以通过 this.props.status和this.props.serverTime得到这些值

    mapDispatchToProps中返回的是一个对象,这个对象中每个属性的值是一个方法,属性名就是组件中使用this.props.XXX()调用的那个XXX,最终这些属性也会变成组件props的一部分

    log验证

    苍白的文字描述得再多,不如用铁打的事实来得直接

    我们在可能有疑问的地方加上log

    这里

       if (firstRender){
                this.logMsgWithKey('初始props', this.props)
            }else{
                this.logMsgWithKey('新的props', this.props)
            }
            firstRender = false
    这里

    export const refreshHomePageTask = (dispatch, param = {}, action) => {
        printf('refreshHomePageTask' + '_请求参数:', param)
        return new Promise((resolve, reject) => {
            resolve(initHomeData())
        }).then((res) => {
            printf('refreshHomePageTask' + '_请求结果:', res)
            dispatch(action(res))
        })
    }
    还有这里

    export const homeIndex = (state = initHomeData(), action) => {
        printf('homeIndex Reducer receive an action:', action)
        switch (action.type) {
            case REFRESH_HOMEPAGE:
                return action.data
            default:
                return state
        }
    }
    执行后得到如下铁证








    展开全文
  • React Native 复习生命周期 关于React Native,我知道的不多
  • React-Native学习笔记之生命周期
  • 不仅可以在react native 的js界面和现有工程的界面之间跳转,而且可以把js写的界面当成一个控件,嵌入到现有的activity,作为原生界面的一部分使用。
  • 今天开始学习react-native,想学的小伙伴们可以一起学习(文章下面有学习视频)大家可以把自己的学习评论在下方1.准备开发环境⚠️MAC 需要 Xcode⚠️window 需要 jdk详细:reactnative.cn/docs/gettin…2.创建项目国内...
  • 项目中已经开始使用react-native-router-flux,这个库比较大,内容也比较丰富,它是react-navigation的增强版,添加了如modal,refresh等功能,使用的过程中一点点总结下来,方便以后再用, 使用前:npm i react-...
  • react native swiper可以实现广告轮播图和应用引导页的效果。如:安装react-native-swiper是第三方组件,通过nmp来安装。在项目的根目录下,通过输入npm install react-native-swiper --save引入在要使用swiper的...
  • React-Native学习笔记React-Native升级
  • 关于scrollView和android 中的使用效果是一样的 被包裹的组件和布局 能够实现滚动效果 注意:该组件适用于zi组件比较少的...class helloReact1 extends Component { render() { return ( ScrollView> Text style=
  • 在proos的例子程序中,可以把Image看成系统定义好的类或者属性,而Greeting看成是我们自己定义的一个类,在react native中称为组件(Component)。那么这样理解的话,source={pic} 就是给Image的成员变量source赋值...
  • 前面介绍了react-navigation的StackNavigator、TabNavigator、DrawerNavigator 的基本使用方法,在实际项目中通常需要嵌套这几种导航方式。下面介绍这几种导航方式的嵌套使用方法。1.StackNavigator与TabNavigator的...
  • React Native开发笔记

    2017-07-24 21:52:37
    介绍React Native开发所需要的基本软件,常用的adb命令和npm命令。以及介绍一些有用的网站。
  • 前言对于存放数据量小且简易的数据我们可以通过AsyncStorage来存储,但对于数据结构复杂、...使用React Native并没有提供使用sqlite的组件,我们可以通过使用第三方组件react-native-sqlite来使用原生的SQLiteDataba
  • 在运行阶段,每次状态(state)或属性(props)发生变化时,都有对应的组件方法将该变化通知给组件进行渲染刷新(关于state和props的介绍可以看上一节react native学习笔记6——Props和State)。下图是经典的组件生命...
  • ReactNative 学习笔记--封装下拉菜单 单个下拉子项 先看整体要做的效果 1.实现原理: 先做一行按钮,使我们要点击弹出菜单列表的按钮,然后计算点击的按钮所在的位置,再通过点击按钮的高度计算出要弹...
  • 本文出自《React Native学习笔记》系列文章。 React Native是基于React的,在开发React Native过程中少不了的需要用到React方面的知识。虽然官方也有相应的Document,但篇幅比较多,学起来比较枯燥。 通过《React ...
1 2 3 4 5 ... 20
收藏数 4,378
精华内容 1,751
关键字:

native react 笔记