react-reduxreact-redux入门


备注

React Redux是一个为Redux提供React绑定的库。

了解Redux存储的React组件称为“容器”,“智能组件”或“高阶组件”(HOC)。要使用Redux,这些组件需要:

  • 订阅商店以获取Redux商店的更新
  • 派遣行动

手动执行此操作意味着在React容器中使用store.subscribestore.dispatch(action)

React Redux通过connect函数简化了Redux存储和React容器组件之间的绑定,该函数将Redux状态属性和Action创建者映射到组件的props。

connect是一个创建更高阶组件的函数。 Connect接受3个函数( mapStateToPropsmapDispatchToPropsmergeProps )并返回一个容器组件,它包装原始组件以使其成为“连接”组件:

import { connect } from 'react-redux';

const Customers = { ... };
const mapStateToProps = (state) => { ... }
const mapDispatchToProps = (dispatch) => { ... }

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

有关完整示例,请参阅示例部分。

由于所有容器组件都需要访问Redux存储,因此推荐的方法是使用React Redux的特殊<Provider>组件,它将存储传递给所有子组件(在内部使用React上下文)。

官方文档: http//redux.js.org/docs/basics/UsageWithReact.html

GitHub回购: https//github.com/reactjs/react-redux

版本

发布日期
5.0.3 2017年2月23日
5.0.2 2017年1月11日
5.0.1 2016年12月14日
5.0.0 2016年12月14日
4.4.6 2016年11月14日
4.4.5 2016年4月14日
4.4.4 2016年4月13日
4.4.3 2016年4月12日
4.4.0 2016年2月6日
4.3.0 2016年2月5日
4.2.0 2016年2月1日
4.1.0 2016年1月28日
4.0.0 二零一五年十月十五日
3.0.0 2015年9月24日
2.0.0 2015年9月1日
1.0.0 2015年8月24日
0.5.0 2015年8月7日
0.1.0 2015年7月12日

完整的例子

假设我们有容器“CustomersContainer”,它将“Customers”哑组件连接到Redux商店。

在index.js中:

import { Component }, React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './redux/rootReducer';
import CustomersContainer from './containers/CustomersContainer';

let store = createStore(rootReducer);

render(
  <Provider store={store}>
    <CustomersContainer />
  </Provider>,
  document.getElementById('root')
);
 

在CustomersContainer中:

import React, { Component } from 'react';
import { connect } from 'react-redux';

// Import action creators
import { fetchCustomers } from '../redux/actions';

// Import dumb component
import Customers from '../components/Customers';

// ES6 class declaration
class CustomersContainer extends Component {
  componentWillMount() {
    // Action fetchCustomers mapped to prop fetchCustomers
    this.props.fetchCustomers();
  }

  render() {
    return <Customers customers={this.props.customers} />;
  }
}

function mapStateToProps(state) {
  return {
    customers: state.customers
  };
}

// Here we use the shorthand notation for mapDispatchToProps
// it can be used when the props and action creators have the same name 
const CustomersContainer = connect(mapStateToProps, { fetchCustomers })(CustomersContainer);

export default CustomersContainer;
 

使用React Redux的Hello World

本指南假设您已经安装了reactreduxreact-routerreact-redux 并配置了reactreduxreact-router 。如果还没有,请这样做。

注意:虽然react-router 不依赖于react-redux ,但我们很可能会在反应应用程序中使用它来进行路由,这使我们很容易使用react-redux。


FILENAME: app.js

'use strict';

import React from 'react';
import { render } from 'react-dom';
import { Router, Route, Link, browserHistory, IndexRoute } from 'react-router';
import { Provider } from 'react-redux';
import store from './stores';

render(
  (
    <Provider store={ store }>
      <Router history={ browserHistory }>
        {/* all the routes here */}
      </Router>
    </Provider>
  ),
  document.getElementById('app')
);
 

这个文件对大多数人来说都是有意义的,我们在这里做的是从./stores 获取商店并使用react-redux 提供的高阶组件Provider 将其传递给所有路由。

这使得商店在整个应用程序中都可用。


现在,让我们考虑一下这种情况 。我们有一个组件UserComponent ,它从user reducer获取数据,并有一个按钮,当点击它时更新商店中的数据。

应用结构

我们的rootReduceruser reducer

const rootReducer = combineReducers({
    user: userReducer,
})
export default rootReducer;
 

我们的userReducer 看起来像这样

const default_state = {
  users: [],
  current_user: {
    name: 'John Doe',
    email: 'john.doe@gmail.com',
    gender: 'Male'
  },
  etc: {}
};

function userReducer( state=default_state, action ) {

  if ( action.type === "UPDATE_CURRENT_USER_DATA" ) {
    return Object.assign( {}, state, { current_user: Object.assign( {}, state.current_user, { [action.payload.field]: action.payload.value } ) } );
  }
  else {
    return state;
  }

}

export default userReducer;
 

我们的actions 文件看起来像这样

export function updateCurrentUserData( data ) {
  return {
    type: "UPDATE_CURRENT_USER_DATA",
    payload: data
  }
}
 

最后,让我们在我们的组件上工作

FILENAME: UserComponent.js

'use strict';

import React from 'react';
import { connect } from 'react-redux';
import * as Action from './actions';

let UserComponent = (props) => {

  let changeUserDetails = (field, value) => {
    // do nothing
  }

  return(
    <div>
      <h1>Hello { props.current_user.name }</h1>
      <p>Your email address is { props.current_user.email }</p>
      <div style={{ marginTop: 30 }}>
        <button onClick={ () => { changeUserDetails('name', 'Jame Smith') } }>Change Name</button>
        <button onClick={ () => { changeUserDetails('email', 'jane@gmail.com') } }>Change Email Address</button>
      </div>
    </div>
  )

}

export default UserComponent;
 

当然这不起作用 ,因为我们尚未将它连接到商店。

如果你想知道,这是一个无状态的功能组件 ,因为我们使用的是redux ,我们并不需要组件的内部状态,这是使用它的正确时间。

react-redux 提供的connect 方法有三个参数

mapStateToPropsmapDispatchToPropsComponent本身。

connect( mapStateToProps, mapDispatchToProps )(Component)


让我们添加连接到我们的组件UserComponent以及mapStateToPropsmapDispatchToProps

我们还要更新我们的changeUserDetails函数,因此在调用时,它会向我们的reducers dispatch 一个action ,并根据我们的reducer将启动并对商店进行更改的动作类型,并且一旦商店更新了react-redux 将重新启动使用新数据渲染我们的组件。

听起来很复杂?它真的不是。

我们的UserComponent.js 看起来像

'use strict';

import React from 'react';
import { connect } from 'react-redux';
import * as Action from './actions';

const mapStateToProps = ( state, ownProps ) => {
  return {
    current_user: state.user.current_user,
  }
}

const mapDispatchToProps = ( dispatch, ownProps ) => {
  return {
    updateCurrentUserData: (payload) => dispatch( Action.updateCurrentUserData(payload) ),
  }
}


let UserComponent = (props) => {

  let changeUserDetails = (field, value) => {
    props.updateCurrentUserData({ field: field, value: value });
  }

  return(
    <div>
      <h1>Hello { props.current_user.name }</h1>
      <p>Your email address is { props.current_user.email }</p>
      <div style={{ marginTop: 30 }}>
        <button onClick={ () => { changeUserDetails('name', 'Jame Smith') } }>Change Name</button>
        <button onClick={ () => { changeUserDetails('email', 'jane@gmail.com') } }>Change Email Address</button>
      </div>
    </div>
  )

}

const ConnectedUserComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(UserComponent)

export default ConnectedUserComponent;
 

我们在这里做了什么

  • mapStateToProps:这使我们能够得到存储和数据发生变化的数据,我们的组件将被重新渲染与新的数据。

    我们的组件只会在我们的组件请求更改商店的数据时重新呈现,而不会在商店中的任何其他数据更改时重新呈现。

  • mapDispatchToProps :这允许我们从我们的组件向所有reducers dispatch actions ..(可以是任何组件),并且根据动作type ,我们的userReducer将启动并返回具有更新数据的新状态。

  • ConnectedUserComponent :最后,我们使用connect 方法将组件连接到商店,方法是传递所有参数并exported 连接的组件。

  • 我们还更新了我们的changeUserDetails函数来调用props上的method 并传入数据。然后, props 会调度我们调用的方法给所有reducers。


注意:

  • 如果我们不从reducer返回一个新状态, react-redux 不会重新渲染我们的组件。

安装或设置

直接使用redux with react 可能看起来有点困难。对于存储更改时要更新的每个component ,您必须将该组件订阅到redux store

React Redux负责处理所有这些,并且可以很容易地编写可以从redux store 请求所需数据的组件,并且只有在这些数据发生变化时才会收到通知。这使我们能够编写真正有效的组件。

要安装react-redux 您只需运行此npm 命令即可

npm install --save react-redux
 

而且你已经完成了。


注意: React Redux依赖于

  • React(版本0.14或更高版本)和
  • 终极版