Reactjs 在容器组件模式中集成分派操作
所以我完全搞不懂如何集成容器和组件模式。我整个上午都在复习示例,但似乎什么都没有。在我之前的第一个项目中,我是如何使用React的,就是在我的视图组件中获取数据,然后使用Reactjs 在容器组件模式中集成分派操作,reactjs,redux,react-redux,Reactjs,Redux,React Redux,所以我完全搞不懂如何集成容器和组件模式。我整个上午都在复习示例,但似乎什么都没有。在我之前的第一个项目中,我是如何使用React的,就是在我的视图组件中获取数据,然后使用@connect将这些数据作为道具向下传递的,该道具可以工作,但此时以“自动”的方式传递给我 import React; ... import {action} from 'path/to/action.js'; @connect((store) => {return{ key: store.property}});
@connect
将这些数据作为道具向下传递的,该道具可以工作,但此时以“自动”的方式传递给我
import React;
...
import {action} from 'path/to/action.js';
@connect((store) => {return{ key: store.property}});
export class Component{
componentWillMount(){
this.props.dispatch(action());
}
}
随着我越来越多地与React合作,我想学习使用Redux进行构建的更“正确”的方法,并更深入地了解正在发生的事情
我设置的是
index.jsx (This renders all of my HOCs)
|
App.jsx (Container)
|
Auth.jsx (Component)
|
Layout.jsx (Component) - Contains app content
--or--
AuthError.jsx (Component) - 401 unauthenticated error page
身份验证是通过外部资源处理的,因此此应用程序不会通过登录或注销控制任何内容。只要从标识用户角色的API接收对象,就不会出现登录/注销状态&已验证布尔值
我希望的是,当应用程序加载时,它将从模拟API获取数据。从那里它将呈现Auth组件。Auth组件将从App.jsx
中获取props
,并呈现Layout.jsx
或authror.jsx
我遇到的问题是如何将其集成。我将省略我认为与这个问题不完全相关的代码行
store.js
import { applyMiddleware, combineReducers, createStore } from 'redux';
import thunk from 'redux-thunk';
import { createLogger } from 'redux-logger';
import promise from 'redux-promise-middleware';
import { composeWithDevTools } from 'redux-devtools-extension';
import reducer from './reducers';
const middleware = applyMiddleware(promise(), thunk, createLogger());
export default createStore(reducer, composeWithDevTools(middleware));
export default function reducer(
state = {
authenticated: null
},
action
) {
switch (action.type) {
case 'AUTH_SUCCESSFUL': {
return {
...state,
authenticated: action.payload.authenticated
};
break;
}
case 'AUTH_REJECTED': {
return {
...state,
authenticated: false
};
}
}
return state;
}
import axios from 'axios';
export function authenticateUser() {
console.log('authenticate user action has been called');
return function(dispatch) {
// nothing runs within this block so it's leading me to believe nothing is being `dispatch`ed
console.log('dispatch', dispatch);
axios
.get('localhost:3004/auth')
.then(response => {
dispatch({ type: 'AUTH_SUCCESSFUL', payload: response.data });
console.log('response', response);
})
.catch(err => {
dispatch({ type: 'AUTH_REJECTED', payload: err });
console.log('error', err);
});
};
}
index.jsx
import React from 'react';
import store from './store.js';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './containers/App.jsx';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { authenticateUser } from '../actions/authActions.js';
import Auth from '../components/Auth.jsx';
class App extends Component {
constructor(props) {
super(props);
this.state = {
authenticated: false // this needs to be set
};
}
componentWillMount() {
console.log('APP PROPS', this.props);
// this.props.actions.authenticateUser();
authenticateUser(); // this runs but doesn't run the dispatch function
// What I think needs to happen here Dispatch an Action and then setState referring back to how I would previous build with React Redux.
}
render() {
return (
<Auth app_name={ApplicationName} authenticated={this.state.authenticated} {...this.props} />
);
}
}
const mapStateToProps = state => {
console.log('redux store auth state', state);
return {
auth: state.auth
};
};
const mapDispatchToProps = dispatch => {
return { actions: bindActionCreators(authenticateUser, dispatch) };
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
import React from 'react';
import { Route } from 'react-router-dom';
import AuthError from './AuthError.jsx';
import Layout from './Layout.jsx';
export default function Auth(props) {
console.log('AUTH PROPS', props);
const renderLayout = () => {
if (props.authenticated == true) {
return <Layout app_name={props.app_name} />;
} else {
return <AuthError />;
}
};
return <Route path="/" render={renderLayout} />;
}
authoctions.js
import { applyMiddleware, combineReducers, createStore } from 'redux';
import thunk from 'redux-thunk';
import { createLogger } from 'redux-logger';
import promise from 'redux-promise-middleware';
import { composeWithDevTools } from 'redux-devtools-extension';
import reducer from './reducers';
const middleware = applyMiddleware(promise(), thunk, createLogger());
export default createStore(reducer, composeWithDevTools(middleware));
export default function reducer(
state = {
authenticated: null
},
action
) {
switch (action.type) {
case 'AUTH_SUCCESSFUL': {
return {
...state,
authenticated: action.payload.authenticated
};
break;
}
case 'AUTH_REJECTED': {
return {
...state,
authenticated: false
};
}
}
return state;
}
import axios from 'axios';
export function authenticateUser() {
console.log('authenticate user action has been called');
return function(dispatch) {
// nothing runs within this block so it's leading me to believe nothing is being `dispatch`ed
console.log('dispatch', dispatch);
axios
.get('localhost:3004/auth')
.then(response => {
dispatch({ type: 'AUTH_SUCCESSFUL', payload: response.data });
console.log('response', response);
})
.catch(err => {
dispatch({ type: 'AUTH_REJECTED', payload: err });
console.log('error', err);
});
};
}
现在在
App.jsx
中,我可以控制authReducer
的状态,并且可以在我的操作中调用authenticateUser()
。但是当我调用authenticateUser()
时,返回分派函数不会运行。我应该在App.jsx
中调度auth操作吗?或者我应该在auth.jsx
中调度auth作为一个道具,然后让App.jsx
获取数据?只是有点迷失在打破这一点,什么样的作品应该做什么工作 您的authenticateUser返回一个函数,您需要实际运行该函数。正确的方法是在mapDispatchToProps中添加属性
const mapDispatchToProps=dispatch=>{
返回{authenticateUser:()=>dispatch(authenticateUser())};
};
然后,在componentWillMount函数中,调用
this.props.authenticateUser()
我将对此做一个简短的解释,以帮助您理解这些模式,并且不再感到困惑(我希望如此) 因此,让我们暂时忘掉减缩器,把重点放在容器、动作创建者和组件模式上 组成部分 很多人在将组件与redux应用程序一起使用时以错误的方式实现组件 redux更好的组件方法是,使用无状态模式实现它(请参阅)。让我们在实践中看到:
// components/Subscribe.js
import React from 'react'
import PropTypes from 'prop-types'
const Subscribe = ({text, confirmSubscription}) =>
<div>
<p>{text}</p>
<button onClick={confirmSubscription}>Confirm</button>
</div>
Subscribe.propTypes = {
subtitle: PropTypes.string.isRequired
}
Subscribe.defaultProps = {
subtitle: ''
}
export default Subtitle
动作创造者
动作创建者(或动作创建者)只是返回动作的集合或函数。简单地说:
// actions/subscription
export const CONFIRM_SUBSCRIPTION = 'actions.confirmSubscription'
export function confirmSubscription() {
return {
type: CONFIRM_SUBSCRIPTION
}
}
现在,我们已经实现了三元组模式,组件,容器和动作创建者,从这里开始,您只需要另外两件事就可以让它与Redux一起工作
- 创建
存储订阅
- 处理
确认订阅
(以防更新应用程序状态)
- 返回新状态
mapStateToProps
,您将收到新状态作为参数,从那里,React将在必要时更新您的组件,如果这些组件是无状态的,PureComponent
(仅适用于单级状态和道具)或自定义应更新组件
要记住的另一件事是不要在组件、容器和动作创建者内部执行获取或异步执行,您可以使用诸如redux-thunk
之类的中间件组成一个定制的中间软件来捕获动作并在将动作发送给还原程序之前进行处理。在App.js
中,您为什么要注释掉//this.props.actions.authenticateUser()而不是直接运行它<代码>authenticateUser()代码>您通过操作
对象将其映射到道具
,这更多是为了说明不同尝试的目的。我用了很多例子试图把这些点联系起来。第一次尝试是直接运行它,然后在mapDispatchToProps
的返回中创建该操作。好的,当您像这样使用mapDispatchToProps
时,您应该使用这个sysntaxthis.props.actions.authenticateUser()
。也就是说,您不应该在componentWillMount
中使用ajax请求,这与在构造函数中使用它是一样的,在ajax请求完成之前可能会调用render
方法。顺便说一下,您不应该使用组件willmount
方法,而应该使用构造函数。好的,这很清楚,我已经在constructor()
函数中修改并运行了分派,而不是componentWillMount
。不,我的意思是通常使用constructor
而不是componentWillMount
,但仍然不应该在它们内部调用ajax请求(不在组件中,也不在构造函数中)。对于ajax请求,您应该使用组件didmount
摆脱mapDispatchToProps中的操作道具。当我试图编辑答案时,它一直告诉我格式不正确,所以我只是将其发布在注释中。我被绊倒的一件事是authenticateUser:dispatch(authActions.authenticateUser())
。我想知道你从哪里得到了authorizations
,因为那不是一个函数。减少到authenticateUser