4

編集: 要約 - 私の質問の最初の原因は実際にはタイプミスでした: 大文字の「G」が原因で機能しませんでした。

ただし、親切な回答者は、タイプミスだけでなく、私が取っていたアプローチの間違った前提にも対処しました-あなたもプロバイダー使用してストアを渡し、接続を使用している場合、彼らの回答はあなたに関連しています. これを反映するために質問のタイトルを更新しました。


私は素晴らしい redux ビデオ<Provider>の指示に従おうとしていますが、react-reduxを使用してストアを渡すことに悲しみを感じています。

私はルートコンポーネントを持っています:

export default class Root extends Component {
   render() {

      const { store } = this.props

      return (
         <Provider store={store}>
            <div>
               <ReduxRouter />
               <DevTools />
            </div>
         </Provider>
      )
   }
}

そして、ストアを使用しようとしているプレゼンテーション コンポーネント:

const ProjectsSummary = (props, {store}) => {
   const state = store.GetState();
   const { projects } = state;

   return (
      <div className="home-projects col-md-10">
          <h3>Projects</h3>
          <ul>
              { projects.map(p => <li key={p.id}>{p.contract.client}</li>) }
          </ul>
      </div>
   )
}

ProjectsSummary.contextTypes = {
   store: React.PropTypes.object
};

class Home extends BasePage {

   render() {
      return (
         <div className="home-page container-fluid">
             {super.render()}
             <HomeLeftBar/>
             <HomePageHeader/>
             <ProjectsSummary/>
         </div>
      )
   }
    }

export default connect()(Home)

「Uncaught TypeError: store.GetState is not a function」が表示されます

ストアはここから来ています:

import configureStore from './store/configureStore'

const store = configureStore({
   security:{
      jwt: 'mock'  // Mock data supplied below: only loaded when this is set.
   }, 
   projects: [
      {
            // elided for brevity
      }
   ]
})

/**
 * Main application render method that attaches it
 * to the HTML page.
 */
render(
   <Root store={store}/>,
   document.getElementById('app')
)

ここに作成されます:

export default (initialState) => {
   const store = createDevStore(initialState)

   if (module.hot) {
      // Enable Webpack hot module replacement for reducers
      module.hot.accept(['../../common/reducers', '../reducers'], () => {
         const nextRootReducer = require('../../common/reducers')
         const nextBrowserReducers = require('../reducers')
         store.replaceReducer(nextRootReducer(nextBrowserReducers))
      })
   }

   return store
}

function createDevStore(initialState){
   if(initialState && initialState.security && initialState.security.jwt === 'mock')
      return mockCreateStore(rootReducer(browserReducers), initialState)
   else
      return finalCreateStore(rootReducer(browserReducers))
}

const mockCreateStore = compose(
   reduxReactRouter({routes, createHistory}),
   applyMiddleware(createLogger()),
   DevTools.instrument()
    )(createStore)

(私のコードではありません。反応ネイティブとブラウザークライアントをサポートするフレームワークであり、私が作業を開始しています)

私は何が欠けていますか?


これをビデオからコピーしています - AddTodo コンポーネントは connect() を使用して「ラップ」されていないことに注意してください:

const AddTodo = (props, { store }) => {
  let input;

  return (
    <div>
      <input ref={node => {
        input = node;
      }} />
      <button onClick={() => {
        store.dispatch({
          type: 'ADD_TODO',
          id: nextTodoId++,
          text: input.value
        })
        input.value = '';
      }}>
        Add Todo
      </button>
    </div>
  );
};
AddTodo.contextTypes = {
  store: React.PropTypes.object
};
4

2 に答える 2

14

この答えは正しいですが、いくつか明確にしたいと思います。

プレゼンテーション コンポーネントとコンテナ コンポーネント、およびその役割について、多くの混乱があるようですconnect()。関連するビデオをもう一度見て、最後まで見ることをお勧めします。

  1. 確かにstore.GetState()、有効な方法ではありません。store.getState()は。
  2. store.getState()手動で使用する場合は、どこかで使用する必要store.subscribe()があるため、常に最新の状態を取得できます。動画から貼り付けたコンポーネントの例AddTodoは、それ自体では機能しません。<strong>store.subscribe(render)一番上に があったため、動画でのみ機能しました。
  3. コースの後半のビデオでは、上からの再レンダリングがどのように面倒になるかについて説明し、その時点でコンテナー コンポーネントを紹介します。connect()後で、手動で記述するよりも、を使用してコンテナー コンポーネントを生成する方が簡単であることを示しconnect()ます。
  4. Homeケースに入れるだけでconnect()は効果がありません。ストアをサブスクライブするコンテナー コンポーネントを生成しますが、引数connect()を指定しないと、ストアをサブスクライブすることさえありません。Usingは、 using および手動の効率的な代替手段です。何かに対して使用しを呼び出したり指定したりすることは決して意味がありません。mapStateToPropsconnect()store.getState()store.subscribe()contextTypesconnect()store.getState()contextTypes

したがって、もう一度要約すると、次のようになります。

  • store.getState()およびstore.subscribe()低レベル API です。それらを使用する場合は、一緒に使用する必要があります。一方が他方なしでは意味がありません。

  • connect()は、小道具を介して必要な情報を子コンポーネントに呼び出しgetState()て渡すことを処理します。subscribe()を使用する場合、 、、またはconnect()は必要ありません。全体のポイントは、それらを抽象化することです。store.getState()store.subscribe()contextTypesconnect()

レッスンでは、これらすべてのツールを教えて、魔法などないことを示します。ただし、通常、実際のアプリではstore.getState()andを使用しないでください。低レベル API にアクセスする特別な理由がない限り、store.subscribe()ほぼ独占的に使用する必要があります。connect()

コードを大まかに次のように書き直します。

// ProjectSummary is a presentational component
// that takes projects as a prop and doesn't care
// where it comes from.
const ProjectsSummary = ({ projects }) => {
  return (
    <div className="home-projects col-md-10">
      <h3>Projects</h3>
      <ul>
        {projects.map(p => <li key={p.id}>{p.contract.client}</li>)}
      </ul>
    </div>
  )
}

// Home by itself is also a presentational component
// that takes projects as a prop. However we will
// wrap it in a container component below using connect().
// Note that I got rid of inheritance: it's an anti-pattern
// in React. Never inherit components; instead, use regular
// composition and pass data as props when necessary.
const Home = ({ projects }) => (
  <div className="home-page container-fluid">
    <BasePage />
    <HomeLeftBar />
    <HomePageHeader />
    <ProjectsSummary projects={projects} />
  </div>
)

// How to calculate props for <Home />
// based on the current state of the store?
const mapStateToProps = (state) => ({
  projects: state.projects
})

// Generate a container component
// that renders <Home /> with props from store.
export default connect(
  mapStateToProps
)(Home)
于 2016-03-11T20:14:27.817 に答える
4

アップデート:

store.GetState()メソッドではありません。

store.getState()方法です。


の使い方connectは少し逆です。

connect最初の引数として関数を取り、ストアと小道具にアクセスできます。反対側に渡すのは、ビュー コンポーネントが として受け取るオブジェクトですprops

const MyWidget = (props) => {
  const { title, data } = props;
  return (<div>{title}{data}</div>);
};
const MyWidgetContainer = connect((store, props) => {
  return { title: props.title, data: store.a.b.widget.data };
})(MyWidget);

それをエクスポートし、プロジェクトの別の場所にインポートしてMyWidget(外部の世界ではウィジェットとコンテナーの違いがわからないため)、タイトルを付ければ、うまくいくはずです。

import MyWidget from "./components/my-widget/";

//...
render ( ) {
   return (
     <MyWidget title="My Title" />
   );
}

MyWidget は、ストアへの独自のアクセス権を持つようになりました。

connectあなたの場合、あなたが見るトランスフォーマー関数を与えなかった、あなたはそれを<Home>に適用しました。つまり、アプリでHomeを使用した場合、ストアにアクセスできHomeContainerます...

これは 100% 問題ありませんが、プレゼンテーション コンポーネントもラップしない限り、プレゼンテーション コンポーネントはストアにアクセスできません。それも問題ありませんが、Home必要な小道具をコンポーネントに渡す必要があることを意味します。

// Home

Home {
  render () {
    { a, b, c } = this.props;
    return (
      <MyWidget a={ a } b={ b } c={ c } />
    );
  }
}
container = connect(/* ... */)(Home);
于 2016-03-11T13:56:21.863 に答える