2017-12-05 6 views
0

いくつかのアニメーションを持つ自分のリアクションルータを試してみる。レンガの壁にぶつけてください。状態を失うことなくインスタンスのリストをレンダリングする方法/コンポーネントを再作成しますか?

私はスクリーンのスタックをレンダリングしています。
スタックをポップまたはプッシュできます。

私の問題は、スタックが変更されたときに状態が失われ、コンストラクタが以前の状態を破壊して(スタックが役に立たなくなる)ということです。 どうすればいいですか?

画面

render() { 
    return (<View 
      {...this.props} 
      onLayout={(event) => this.onLayout(event)} 
      pointerEvents={this.state.isAnimating ? 'none' : undefined} 
      > 
     { this.renderStackOfScreens() } 
    </View>); 
}; 

renderStackOfScreens() { 
    // Render screens. 
    return this.state.stackOfScreens 
    .map((eachScreen, index) => { 

     // Render second last screen IF animating. Basically because we have a screen animating over the top. 
     if (index === this.state.stackOfScreens.length - 2 && this.state.isAnimating) { 
      return (
       <Animated.View 
        key={eachScreen.props.screenId + '_parent'} 
        style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}> 
        { eachScreen } 
       </Animated.View> 
      ); 
     } 

     // Render last screen which is animated. 
     if (index === this.state.stackOfScreens.length - 1) { 
      return (
       <Animated.View 
        key={eachScreen.props.screenId + '_parent'} 
        style={this.getOffset(this.state.animatedScreenOffset)}> 
        { eachScreen } 
       </Animated.View> 
      ); 
     } 
    }) 
    // Remove the undefined values. 
    .filter((eachScreen) => !!eachScreen); 
} 

ここ https://pastebin.com/BbazipKtを完全な例を見ることができますレンダリング画面(この後、私たちがオン状態であるスタックにプッシュ)

/** 
* Create a new React.Element as a screen and pass props. 
*/ 
createNewScreen = (screenName: string, props: ?any = {}): any => { 

    // Props is not an object. 
    if (typeof props !== 'object') { 
     Logger.error(`Passed props to screen name ${screenName} wasn't an object or undefined. Will error next screens.`); 
     return; 
    } 

    let propsUnlocked = JSON.parse(JSON.stringify(props)); 

    // Add unique screen it. 
    const uniqueScreenKey = this.generateRandomUniqueID(); 
    propsUnlocked.key = uniqueScreenKey; 
    propsUnlocked.screenId = uniqueScreenKey; 
    propsUnlocked.navKing = this; 
    propsUnlocked.screenName = screenName; 

    // Find the original screen to copy from. 
    // This just copies the 'type' 
    // $FlowFixMe 
    return React.createElement(this.findScreenNameComponent(screenName).type, propsUnlocked); 
} 

を作成します。

画面の種類は合格ですユニークな子供たちの中でエド。

答えて

2

コンポーネントがアンマウントされると、コンポーネントの状態は永遠に消えます。 「まあ、コンポーネントへの可変参照があるので、アンマウントされていても状態はそのまま維持されています」と思うかもしれません。いいえ、反応はそのようには機能しません。コンポーネントをアンマウントすることは、コンポーネントをアンマウントすることと同じです。たとえ "同じ"コンポーネントを再読み込みしても、Reactに関する限り、新しいコンストラクタ呼び出し、ライフサイクルの実装など、まったく新しいコンポーネントです。したがって、Reactコンポーネント自体を配列で保持するというアプローチを断念する必要があります履歴スタックとして使用します。

私は知っています。私を信じて、私は同じ問題に遭遇しました。

解決策は、コンポーネント自体からビュー/スクリーン状態を引き出し、それらを親に持ち上げることです。本質的には、状態を親の配列に保持しておき、ビュー/スクリーン自体に小道具として渡します。これはと思われます。は、直感的で直感的で「非反応的」な方法ですが、it actually is in line with how React is intended to be usedと思われます。州は、一般的に、最も近い共通の祖先のレベルまで "持ち上げ"て、すべてのコンポーネントがそこからアクセスする必要があります。この場合、ビュー/スクリーンそのもののレベルが以上の状態にアクセスする必要があるため、持ち上げる必要があります。

ここにいくつかの擬似コードを示します。

今、あなたのアプリケーションは次のようにみかん構造化されているようだ:

// App state 
state: { 
    // stackOfScreens is React components. 
    // This won't work if you're trying to persist state! 
    stackOfScreens: [ 
    <Screen />, 
    <Screen />, 
    <Screen /> 
    ] 
} 

// App render function 
render() { 
    return <div> 
    { 
     this.state.stackOfScreens.map((ea, i) => { 
     return <View key={i} >{ea}</View> 
     } 
    } 
    </div> 
} 

代わりに、それは次のようにする必要があります:

// App state 
state: { 
    // stackOfScreens is an array of JS objects. 
    // They hold your state in a place that is persistent, 
    // so you can modify it and render the resulting 
    // React components arbitrarily 
    stackOfScreens: [ 
    { 
     name: "screen#1", 
     foo: "Some sort of 'screen' state", 
     bar: "More state, 
     baz: "etc." 
    }, 
    { 
     name: "screen#2", 
     foo: "Some sort of 'screen' state", 
     bar: "More state, 
     baz: "etc." 
    }, 
    { 
     name: "screen#3", 
     foo: "Some sort of 'screen' state", 
     bar: "More state, 
     baz: "etc." 
    }, 
    ] 
} 

// App render function 
render() { 
    return <div> 
    { 
     this.state.stackOfScreens.map((ea, i) => { 
     return <View key={i} > 
      <Screen stateData={ea} callback={this.screenCallback} /> 
     </View> 
     } 
    } 
    </div> 
} 

お知らせその画面コンポーネントのcallback小道具の追加レンダリングしています。スクリーン内からレンダリングされたスクリーン "状態"(実際には親で追跡される)への変更をトリガーできるようになります。

+0

各画面はコンポーネントの「タイプ」ですが、どのようにレンダリングしますか? 私のコード例をここにプッシュしました: https:// pastebin。com/BbazipKt –

+0

また、前の画面をすべてレンダリングするとパフォーマンスが低下しますか? (私はモバイルheheでこれをやっています) –

+1

@OliverDixonそれはちょうど擬似コードであり、必ずしもすべての画面をレンダリングする必要はありません。 ReactCSSTransitionGroupを見て、コンポーネントのマウント/アンマウントをアニメーション化する良い方法を探してください。このタイプの場合、コンポーネント「タイプ」を各スクリーンの状態オブジェクトのプロパティとして保持し、それを使用してどのタイプのコンポーネントをレンダリングするかを決定することができます。 – jered

関連する問題