0

受@grabbou的https://github.com/facebook/react-native/issues/6268启发,在此问题末尾添加了解决方案

帷幕升起,出现了第一个场景“Scene1”。Scene1 是一个显示组件,用框架中的 ' connect'包装,react-redux用于将状态和操作绑定到它们的道具。动作工作得很好,并在屏幕上呈现状态,计数器。

向前点击到第二个场景'Scene2',和第一个组件完全一样,但是道具(和Scene1一样) 是passProps在.renderSceneNaviagator

一切正常,动作被正确调度,您可以在跟踪上看到,render调用函数来绘制计数器,再次您可以在跟踪中看到,但不工作!。Scene1 中的内部组件日志!怎么了?

这是跟踪,直接进入 Scene2 并单击两次 <+> 以增加状态。

痕迹

这是一个 bug-Native React?

我在用

  • “反应原生”:“0.19.0”,
  • "react-redux": "4.1.2",
  • “redux”:“3.1.7”,

这是所有的代码,如果你能帮助我。对演示文稿的风格化没有任何让步,因此屏幕上的结果非常简单。

1. index.ios.js的简单代码

    'use strict';
    import React, {
      AppRegistry,
    } from 'react-native';

    import App from './src/App'

    AppRegistry.registerComponent('App', () => App);

2.这是App.js的代码:

'use strict';
import React, {
  Navigator,
  Component,
  View, ListView, ScrollView,
  Text, TouchableOpacity
} from 'react-native';

import { Provider, connect } from "react-redux";
import { createStore, applyMiddleware, combineReducers, bindActionCreators } from "redux";
import thunkMiddleware from "redux-thunk";
import createLogger from "redux-logger";

2.1还原部分_

// REDUX BEGIN
//Actions
const INCREMENT = 'INCREMENT'
const DECREMENT = 'DECREMENT'
//Actions creators
const increment = () => ({ type: INCREMENT })
const decrement = () => ({ type: DECREMENT })
//Redux Initial State
const initialState = {
  counter: 0
}
//Reducer
const reducer = (state = initialState, action = {}) => {
  let delta = 1
  switch (action.type) {
  case DECREMENT: delta = -1;
  case INCREMENT:
    return Object.assign({}, state, { counter: state.counter+delta })
  default:
    return state
  }
}
//Redux Middelware
const loggerMiddleware = createLogger();
const createStoreWithMiddleware = applyMiddleware(
  thunkMiddleware,
  loggerMiddleware
)(createStore);
//Wrapper to bind state and actions to props on Presentational Component
const connectComponent = (component) => connect(
    (state) => ({
      counter: state.counter
    }),
    (dispatch) => ({
      increment: () => dispatch(increment()),
      decrement: () => dispatch(decrement())
    })
  )(component)
// REDUX END

2.2 App 根目录,带有ProviderNavigator

// APP
export default class App extends Component {
  render () {
    return (
      <Provider store={createStoreWithMiddleware(reducer, initialState)}>
        <Navigator style={{flex: 1}}

          initialRoute={{
            name: 'Scene1',
            component: connectComponent(Scene1),
          }}

          renderScene={ (route, navigator) => {
            const Component = route.component;
            return (
              <View style={{flex: 1, marginTop:40}}>
                <Component navigator={navigator} route={route} {...route.passProps} />
              </View>
            );
          }}
        />
      </Provider>
    )
  }
}

2.3. 两个场景中用于渲染计数器的内部组件。有一些跟踪,以显示shouldComponentUpdate被触发并返回 True(你必须更新!)跟踪时间以显示在调度操作后仅几毫秒被调用。和其他显示该render功能已达到,但未在 Scene2 中渲染。痕迹显示这个组件他一直以为是Scene1!!

class Counter extends Component{
  constructor (props, context){
    super(props, context);
  }

  shouldComponentUpdate(nextProps, nextState){

    //Begin log
    const repeat = (str, times) => (new Array(times + 1)).join(str);
    const pad = (num, maxLength) => repeat(`0`, maxLength - num.toString().length) + num;
    const formatTime = (time) => `@ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}`;
    console.log('shouldComponentUpdate '+this.props.route.name+ ': '+ (nextProps.counter !== this.props.counter) +' '+formatTime(new Date()));
    //End log

    return nextProps.counter !== this.props.counter;
  }


  render() {
    console.log('onRender: '+this.props.counter);
    return (
      <View>
        <Text style={{fontSize: 100}}>{this.props.counter}</Text>
        <TouchableOpacity onPress={()=>{this.props.increment()}} ><Text style={{fontSize: 40}}>{'<'}+{'>'}</Text></TouchableOpacity>
        <TouchableOpacity onPress={()=>{this.props.decrement()}} ><Text style={{fontSize: 40}}>{'<'}-{'>'}</Text></TouchableOpacity>
        <Text>----</Text>
      </View>
    )
  }
}

2.4. 两个场景,是相等的,只是前进或后退的按钮

class Scene1 extends Component {
  render() {
    return (
      <View>
        <Text style={{fontSize: 40}}>Scene1</Text>
        <Counter {...this.props}/>
        <TouchableOpacity onPress={()=>{
          this.props.navigator.push({
            name: 'Scene2',
            component: Scene2,
            passProps: {...this.props}
           })
        }}>
          <Text style={{fontSize: 20}}>{'<'}Forward{'>'} to Scene2</Text>
        </TouchableOpacity>
      </View>
    )
  }
}


class Scene2 extends Component {
  render() {
    return (
      <View>
        <Text style={{fontSize: 40}}>Scene2</Text>
        <Counter {...this.props}/>
        <TouchableOpacity onPress={()=>{
          this.props.navigator.pop()
        }} >
            <Text style={{fontSize: 20}}>{'<'}Back{'>'} to Scene1</Text>
          </TouchableOpacity>
      </View>
    )
  }
}

最后一些“硬拷贝”来展示“表演”

显示计数器的 Scene2 和用于调度操作的两个按钮。单击这些操作不会呈现计数器,但会正确分派这些操作。 显示计数器的 Scene2

只需转到 Scene2 并单击两次 <+> 即可递增计数器。

Counter组件是他的跟踪显示route.name,但它显示在 Scene1 上!这里有什么问题?

痕迹

好了,戏结束了,大幕已经落下。

这是一个非常戏剧性的场景。(只是场景2)

我想知道为什么它不起作用。

本机反应问题?

谢谢大家

解决方案

来自https://github.com/facebook/react-native/issues/6268

@grabbou 启发了这些变化,他建议将所有 App 包装为一个容器,然后将 Store 和 Actions 作为简单的道具传递给所有场景。

要进行这些更改,请创建一个新组件 RootComponent 并将应用程序连接到 Redux Store 和 Actions,如下所示。

export default class RootComponent extends Component {
  render () {
    const AppContainer = connectComponent(App); //<< App has to be container
    return (
      <Provider store={createStoreWithMiddleware(reducer, initialState)}>
        <AppContainer/>
      </Provider>
    )
  }
}

然后 App 更改删除 Provider 并将 Scene1 作为哑组件传递,并且 renderScene pass {...this.props} insted of {...route.passProps}

class App extends Component {
  render () {
    return (
        <Navigator style={{flex: 1}}

          initialRoute={{
            name: 'Scene1',
            component: Scene1,
          }}

          renderScene={ (route, navigator) => {
            const Component = route.component;
            return (
              <View style={{flex: 1, marginTop:40}}>
                <Component navigator={navigator} route={route} {...this.props} />
              </View>
            );
          }}
        />
    )
  }
}

从 Scene1 中的 navigator.push 中移除 passProps,因为在 renderScene 中已经作为默认值传递

<TouchableOpacity onPress={()=>{
          this.props.navigator.push({
            name: 'Scene2',
            component: Scene2,
            //passProps: {...this.props}
           })
        }}>

这就是所有人!

谢谢

4

1 回答 1

0

注意:这只是作者提供的上述解决方案的复制/粘贴。

来自https://github.com/facebook/react-native/issues/6268

@grabbou 启发了这些变化,他建议将所有 App 包装为一个容器,然后将 Store 和 Actions 作为简单的道具传递给所有场景。

要进行这些更改,请创建一个新组件 RootComponent 并将应用程序连接到 Redux Store 和 Actions,如下所示。

export default class RootComponent extends Component {
  render () {
    const AppContainer = connectComponent(App); //<< App has to be container
    return (
      <Provider store={createStoreWithMiddleware(reducer, initialState)}>
        <AppContainer/>
      </Provider>
    )
  }
}

然后 App 更改删除 Provider 并将 Scene1 作为哑组件传递,并且 renderScene pass {...this.props} insted of {...route.passProps}

class App extends Component {
  render () {
    return (
        <Navigator style={{flex: 1}}

          initialRoute={{
            name: 'Scene1',
            component: Scene1,
          }}

          renderScene={ (route, navigator) => {
            const Component = route.component;
            return (
              <View style={{flex: 1, marginTop:40}}>
                <Component navigator={navigator} route={route} {...this.props} />
              </View>
            );
          }}
        />
    )
  }
}

从 Scene1 中的 navigator.push 中移除 passProps,因为在 renderScene 中已经作为默认值传递

<TouchableOpacity onPress={()=>{
      this.props.navigator.push({
        name: 'Scene2',
        component: Scene2,
        //passProps: {...this.props}
       })
    }}>

这就是所有人!

谢谢

于 2016-03-04T16:40:23.803 回答