使用 <Provider> 通过上下文传递商店在基于 connect() 的场景中不起作用 [英] Passing store through context with <Provider> not working in connect() based scenario

查看:14
本文介绍了使用 <Provider> 通过上下文传递商店在基于 connect() 的场景中不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

摘要 - 我的问题的最初原因实际上是一个错字:由于大写的G",它不起作用.

然而,友好的回答者不仅解决了打字错误,而且还解决了我采用的方法中的错误前提 - 如果您也使用 Provider 使用 connect 传递 store,那么他们的答案与您相关.我已经更新了问题的标题以反映这一点.

<小时>

我正在尝试按照 很棒的 redux 视频,但是使用 react-redux 中的 <Provider> 传递商店而感到悲伤.

我有一个根组件:

export default class Root extends Component {使成为() {const { store } = this.props返回 (<提供者商店={商店}><div><ReduxRouter/><开发工具/>

</提供者>)}}

还有一个试图使用 store 的展示组件:

const ProjectsSummary = (props, {store}) =>{const state = store.GetState();const { 项目 } = 状态;返回 (<div className="home-projects col-md-10"><h3>项目</h3><ul>{projects.map(p => <li key={p.id}>{p.contract.client}</li>) }

)}ProjectsSummary.contextTypes = {商店:React.PropTypes.object};class Home 扩展 BasePage {使成为() {返回 (<div className="主页容器流体">{super.render()}<HomeLeftBar/><HomePageHeader/><项目摘要/>

)}}导出默认连接()(主页)

我收到未捕获的类型错误:store.GetState 不是函数"

商店来自这里:

从'./store/configureStore'导入configureStoreconst store = configureStore({安全:{jwt: 'mock'//下面提供的模拟数据:仅在设置时加载.},项目:[{//为简洁起见省略}]})/*** 附加它的主要应用程序渲染方法* 到 HTML 页面.*/使成为(<根存储={存储}/>,document.getElementById('app'))

并在此处创建:

export default (initialState) =>{const store = createDevStore(initialState)如果(模块.热){//为 reducer 启用 Webpack 热模块替换module.hot.accept(['../../common/reducers', '../reducers'], () => {const nextRootReducer = require('../../common/reducers')const nextBrowserReducers = require('../reducers')store.replaceReducer(nextRootReducer(nextBrowserReducers))})}退货商店}函数 createDevStore(initialState){if(initialState &&initialState.security &&initialState.security.jwt === 'mock')返回 mockCreateStore(rootReducer(browserReducers), initialState)别的返回 finalCreateStore(rootReducer(browserReducers))}const mockCreateStore = compose(reduxReactRouter({routes, createHistory}),应用中间件(createLogger()),DevTools.instrument())(创建商店)

(不是我的代码,一个支持 React Native 和浏览器客户端的框架,我正在开始工作)

我错过了什么?

<小时>

我正在从视频中复制此内容 - 请注意,AddTodo 组件未使用 connect()包装":

const AddTodo = (props, { store }) =>{让输入;返回 (<div><输入参考={节点=>{输入 = 节点;}}/><button onClick={() =>{store.dispatch({类型:'ADD_TODO',id: nextTodoId++,文本:输入值})输入值 = '';}}>添加待办事项

);};AddTodo.contextTypes = {商店:React.PropTypes.object};

解决方案

这个答案是正确的,但我想澄清一些事情.

您似乎对展示组件和容器组件以及 connect() 的作用有很多困惑.建议你再看一遍相关视频,一定要看完.

  1. 确实,store.GetState() 不是一个有效的方法;store.getState() 是.
  2. 如果您手动使用 store.getState() 您必须也在某处使用 store.subscribe() 以便您始终获得最大收益最近状态.您从视频中粘贴的示例 AddTodo 组件本身无法正常工作——它只能在视频中工作,因为我们有一个 store.subscribe(render)非常顶级.
  3. 本课程后面的视频讨论了从顶部重新渲染如何变得麻烦,此时我们将介绍容器组件.稍后我们将展示使用 connect() 生成容器组件比手动编写它们更容易——在这种情况下,connect() 负责订阅商店.
  4. 在您的情况下,仅将 Home 包装在 connect() 中是无效的.connect() 生成订阅 store 的容器组件,但如果您不指定 mapStateToProps 参数,它甚至不会订阅 store.使用 connect() 是使用 store.getState()store.subscribe()contextTypes 的有效替代方法 手动. 两者在某些东西上使用 connect() 并调用 store.getState() 永远没有意义或指定 contextTypes.

所以,再次总结:

课程教您所有这些工具,向您展示没有魔法.然而通常你不应该在实际应用中使用 store.getState()store.subscribe() .您应该几乎只使用 connect() 除非您有非常具体的原因访问低级 API.

我会大致像这样重写你的代码:

//ProjectSummary 是一个展示组件//将项目作为道具并且不在乎//它来自哪里.const ProjectsSummary = ({项目}) =>{返回 (<div className="home-projects col-md-10"><h3>项目</h3><ul>{projects.map(p => <li key={p.id}>{p.contract.client}</li>)}

)}//Home 本身也是一个展示组件//将项目作为道具.然而我们会//使用 connect() 将其包装在下面的容器组件中.//请注意,我摆脱了继承:这是一种反模式//在反应中.永远不要继承组件;相反,使用常规//组合并在必要时将数据作为道具传递.const Home = ({项目}) =>(<div className="主页容器流体"><BasePage/><HomeLeftBar/><HomePageHeader/><ProjectsSummary projects={projects}/>

)//如何计算<Home/>的道具//基于商店的当前状态?const mapStateToProps = (状态) =>({项目:state.projects})//生成容器组件//渲染 <Home/>与商店的道具.导出默认连接(映射状态到道具)(家)

Edit: Summary - the initial cause of my question was actually a typo: it wasn't working due to a capital 'G'.

However, the kind answerers addressed not only the typo, but the wrong premise in the approach I was taking - if you too are passing store using Provider and using connect, their answers are relevant to you. I have updated the title of the question to reflect this.


I am trying to follow the instructions in the awesome redux videos , but have come to grief with passing down the store using <Provider> from react-redux.

I have a root component:

export default class Root extends Component {
   render() {

      const { store } = this.props

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

And a presentation component trying to use store:

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)

I get "Uncaught TypeError: store.GetState is not a function"

The store is coming from here:

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')
)

and is created here:

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)

(Not my code, a framework that supports react native and browser client, which I am starting work in)

What am I missing?


I am copying this from the video - note that AddTodo component is not "wrapped" using 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
};

解决方案

This answer is correct but I would like to clarify a few things.

You seem to have a lot of confusion around presentational and container components, and the role of connect() there. I suggest you to watch the relevant videos again, and make sure you watch them to the very end.

  1. Indeed, store.GetState() is not a valid method; store.getState() is.
  2. If you use store.getState() manually you have to also use store.subscribe() somewhere so you always get the most recent state. The example AddTodo component you pasted from the video will not work by itself—it only worked in the video because we had a store.subscribe(render) at the very top.
  3. Later videos in the course discuss how re-rendering from the top can get cumbersome, at which point we introduce container components. And later we show that it’s easier to generate container components using connect() than write them by hand—in this case, connect() takes care of subscribing to the store.
  4. Merely wrapping Home in connect() in your case has no effect. connect() generates a container component that subscribes to the store, but it won’t even subscribe to the store if you don’t specify the mapStateToProps argument. Using connect() is an efficient replacement for using store.getState(), store.subscribe() and contextTypes manually. It never makes senses to both use connect() on something and call store.getState() or specify contextTypes.

So, to sum up again:

The lessons teach you all of these tools to show you that there is no magic. However usually you should not be using store.getState() and store.subscribe() in real apps. You should almost exclusively use connect() unless you have a very specific reason why you access low-level APIs.

I would rewrite your code roughly like this:

// 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)

这篇关于使用 &lt;Provider&gt; 通过上下文传递商店在基于 connect() 的场景中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆