受@grabbou的https://github.com/facebook/react-native/issues/6268启发,在此问题末尾添加了解决方案
帷幕升起,出现了第一个场景“Scene1”。Scene1 是一个显示组件,用框架中的 ' connect
'包装,react-redux
用于将状态和操作绑定到它们的道具。动作工作得很好,并在屏幕上呈现状态,计数器。
向前点击到第二个场景'Scene2',和第一个组件完全一样,但是道具(和Scene1一样) 是passProps
在.renderScene
Naviagator
一切正常,动作被正确调度,您可以在跟踪上看到,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 根目录,带有Provider和Navigator
// 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 并单击两次 <+> 即可递增计数器。
该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}
})
}}>
这就是所有人!
谢谢