反应路由器 - 无法传递商店

react router - unable to pass store down

我无法使商店对子组件可用。

该设置是一个以 Symfony 作为后端的 SPA,尽管这对此事没有影响。

Webpack 的入口点是文件:

/client/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, compose } from 'redux';
import ReduxPromise from 'redux-promise';
import Root from './App';
import registerServiceWorker from './registerServiceWorker';
import reducers from './pages/combine_reducers';

let composeEnhancers = typeof(window) !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose

const store = createStore(
   reducers,
   composeEnhancers(
      applyMiddleware(ReduxPromise)
   )
)

ReactDOM.render(
     <Root store={store} />
, document.querySelector('#root')
);

registerServiceWorker();

此类应用程序位于:

/client/App.js

import React from 'react';
import PropTypes from 'prop-types';
import { Provider } from 'react-redux';
import {
  BrowserRouter as Router,
  Route,
  Link,
  Switch
} from 'react-router-dom';

import HomePage from './pages/home/';
import AccountPage from './pages/account/';


const Root = ({ store }) => {
return(
    <Provider store={store}>
            <div className="App">
                <header className="App-header">
                    <h1 className="App-title">Welcome to React</h1>
                </header>
                <Router>
                    <div>
                        <Link to="/account">Account</Link>
                        <Link to="/">Home</Link>
                        <div>
                            <Switch>
                                <Route path="/account" component={AccountPage} />
                                <Route path="/" component={HomePage} />
                            </Switch>
                        </div>
                    </div>
                </Router>
            </div>
</Provider>
)
}


Root.propTypes = {
   store: PropTypes.object.isRequired
}

export default Root;

到目前为止一切顺利。该商店在 App.js 有售。 但在下一个层次上就不是这样了。如您所见,我正在尝试使用 connect() 使商店可用。

/client/pages/home/index.js

import React from 'react';
import { connect } from 'react-redux';
import Register from '../common/register/';
import PropTypes from 'prop-types';

class Home extends React.Component {
   constructor(props){
     super(props)
     console.log(props);
   }

    render() {
        return (
            <div>
                <h1> Hello World from home! </h1>
                <Register />
            </div>
        );
    }
}

Home.propTypes = {
   store: PropTypes.object.isRequired
}

const mapStateToProps = (state) => {
   return {
        store: state.store,
   }
}


export default connect(mapStateToProps)(Home)

在较低级别的注册组件中,我可以提交表单,但商店不可用,我无法捕获来自服务器的响应。

/client/pages/common/register/index.js

import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import RegisterForm from './containers/register';
import { actionSubmitRegister } from './actions/';
import PropTypes from 'prop-types';

class Register extends React.Component{
    constructor (props) {
        super(props);
        this.state = {
           registerResponse: '',
        }
        this.onSubmitRegister = this.onSubmitRegister.bind(this);
    }

onSubmitRegister (event) {
    event.preventDefault();
    let submitForm = new Promise((resolve, reject) => {
        actionSubmitRegister(this.props.form.RegisterForm.values);
    });
    submitForm.then((response) => {
        console.log('response',response);
        this.setState({registerResponse:     this.props.submit_register.data});
        console.log('registerResponse', this.state.registerResponse);
    }).catch((error) => {
        console.log(error);
    });
}

render(){           
    return (
        <div>
            <div>
                <RegisterForm
                    submitRegister={this.onSubmitRegister}
                />
                <h3>{this.state.registerResponse}</h3>
            </div>
        </div>
        )
}
}
/*
Register.propTypes = {
    store: PropTypes.object.isRequired
}
*/
const mapStateToProps = (state) => {
    return {
        form: state.form,
        submit_register: state.submit_register,
    }
}

function mapDispatchToProps(dispatch){
    return bindActionCreators({actionSubmitRegister}, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(Register);

mapStateToProps 中,您映射 store: state.store 但通常您使用此方法将单个道具从您的状态映射到组件中的道具,而不是映射整个商店(如果可能的话) . 例如:

form: state.form

您无法访问 props 中的商店对象的原因是您没有通过 props 将其传递下去。 react-redux 库中的提供程序,使其可供元素树下的所有子项使用。 Store 是通过 React 的上下文 API 提供的,而不是通过道具提供的。

"Context is designed to share data that can be considered “global” for a tree of React components."

所以在 Provider 的子组件中,我们现在可以做类似的事情

render() {
 const { store } = this.context;
 console.log(store)
 return(
 ...
 )
}

这与 react-redux 的连接 HOC 能够访问商店并随后访问 mapStateToProps 或利用商店的 dispatch 方法访问 mapDispatchToProps 的方式相同。

另外我认为 Provider 要求它的子元素是一个 React 组件。 查看此 tutorial 以获得更多 in-depth 解释。

收到上面的输入后,我检查了我的代码并让它工作。

实际上主要问题出在 /client/pages/common/register/index.js 文件上,但我发布整个链供参考:

/client/index.js

没什么可改变的

/client/App.js

propTypes的引用好像不是必须的,所以就去掉了。

import React from 'react';
import { Provider } from 'react-redux';
import {
  BrowserRouter as Router,
  Route,
 Link,
 Switch
} from 'react-router-dom';

import HomePage from './pages/home/';
import AccountPage from './pages/account/';


const Root = ({ store }) => {
    return(
        <Provider store={store}>
            <div className="App">
                <header className="App-header">
                    <h1 className="App-title">Welcome to React</h1>
                </header>
                <Router>
                    <div>
                        <Link to="/account">Account</Link>
                        <Link to="/">Home</Link>
                        <div>
                            <Switch>
                                <Route path="/account" component={AccountPage} />
                                <Route path="/" component={HomePage} />
                            </Switch>
                        </div>
                    </div>
                </Router>
            </div>
    </Provider>
    )
}

export default Root;

/client/pages/home/index.js

这里似乎不需要 propTypes 和 connect()。

import React from 'react';
import Register from '../common/register/';

class Home extends React.Component {
    constructor(props){
        super(props)
    }

    render() {
        return (
            <div>
                <h1> Hello World from home! </h1>
                <Register />
            </div>
        );
    }
}

export default Home;

/client/pages/common/register/index.js

这里的主要问题是 onSubmitRegister() 方法。 promise 设置不正确,我直接引用操作而不是使用 this.props。 React 似乎不喜欢那样。

import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import RegisterForm from './containers/register';
import { actionSubmitRegister } from './actions/';

class Register extends React.Component{
    constructor (props) {
        super(props);
        this.state = {
            registerResponse: '',
        }
        this.onSubmitRegister = this.onSubmitRegister.bind(this);
    }

onSubmitRegister (event) {
    event.preventDefault();
    let submitForm = new Promise((resolve) => {
        resolve(this.props.actionSubmitRegister(this.props.form.RegisterForm.values));
    });
    submitForm.then((result) => {
        let data = result.payload.data;
        this.setState({registerResponse: data.message});
    }).catch((error) => {
        console.log(error);
    });
}

render(){           
    return (
        <div>
            <div>
                <RegisterForm
                    submitRegister={this.onSubmitRegister}
                />
                <h3>{this.state.registerResponse}</h3>
            </div>
        </div>
        )
}
}

const mapStateToProps = (state) => {
    return {
        form: state.form,
        submit_register: state.submit_register,
    }
}

function mapDispatchToProps(dispatch){
    return bindActionCreators({actionSubmitRegister}, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(Register);