Redux,如果我想访问数据,是否必须在所有容器中导入存储?
Redux, Do I have to import store in all my containers if I want to have access to the data?
也许我并没有全神贯注于 redux,但我看到的所有示例并没有真正在容器之间访问太多状态,所以我没有看到 store.getState() 的太多用法, 但即使你想发货,你也需要访问商店,对吗?
所以,除了导入
从 'path/to/store/store'
导入商店
在我想要 getState() 或 "dispatch" 的每个文件中,我如何才能访问该状态,因为如果我不包含它,存储是未定义的。
如果您使用 react-redux
包,您将最终用 store
道具将组件包装在 Provider
中。这将在 React 上下文中设置您的单个商店,然后从子组件中的 connect
方法访问它。 connect
方法采用两个函数(mapStateToProps 和 mapDispatchToProps),它们是您从商店获取状态和发送消息的挂钩。
一般来说,您只想制作可以访问商店的顶级容器组件——它们会将任何必要的数据或动作分派作为道具传递给它们的子组件。这是 "smart" 和 "dumb" 组件之间的区别 - "smart" 组件了解 Redux store/state,而 "dumb" 组件只是将道具传递给它们并且不知道更大的应用程序状态。
然而,即使只是将存储传递给容器组件也会变得乏味。这就是 React-Redux 提供一个开箱即用的组件来包装整个应用程序的原因。 Check it out 在文档中。这是 Provider
组件,当你用它包装整个应用程序时,你只将商店传递给组件 once:
import createStore from '../store';
const store = createStore()
class App extends Component {
render() {
return (
<Provider store={store}>
<MainAppContainer />
</Provider>
)
}
}
正如您在此处看到的,我有一个单独的配置文件,仅适用于我的商店,因为您可以进行大量修改,对于任何远程复杂的应用程序,您会发现自己对诸如使用compose 应用中间件。
然后您剩余的任何 "smart" 组件(通常是包装器)都需要监听存储。这是使用 connect 方法完成的。这允许您将状态片段映射到您的组件属性以及将操作作为属性分派。
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as actionCreators from './actionCreators';
const mapStateToProps = function(state){
return {
something: state.something,
}
}
const mapDispatchToProps = function (dispatch) {
return bindActionCreators({
getSomething: actionCreators.getSomething,
}, dispatch)
}
class MainAppContainer extends Component {
componentDidMount() {
//now has access to data like this.props.something, which is from store
//now has access to dispatch actions like this.props.getSomething
}
render() {
//will pass down store data and dispatch actions to child components
return (
<div>
<ChildComponent1 something={this.props.something} />
<ChildComponent2 getSomething={this.props.getSomething} />
</div>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MainAppContainer)
因为您总是将调度操作和数据作为属性传递给您的子组件,所以您只需使用 this.props
.
引用该组件上的那些
基于上面的示例,您会看到因为我将 this.props.something
传递给 ChildComponent1
,它可以访问商店中的 something
数据,但它没有访问 getSomething
调度操作。同样,ChildComponent2
只能访问 getSomething
调度操作,但不能访问 something
数据。这意味着您只将组件公开给他们从商店中需要的东西。
例如,因为 ChildComponent2
作为 getSomething
传递给调度操作,在我的 onClick
中我可以调用 this.props.getSomething
并且它将调用调度操作 无需访问商店。以同样的方式它可以继续向下传递 getSomething
到另一个子组件并且该组件可以调用它 and/or 向下传递它并且循环可以无限期地继续。
class ChildComponent2 extends Component {
render() {
return (
<div>
<div onClick={this.props.getSomething}>Click me</div>
<NestedComponent getSomething={this.props.getSomething} />
</div>
)
}
}
根据评论编辑
虽然这与问题没有直接关系,但在评论中您似乎对操作有些困惑。我实际上并没有在这里定义动作 getSomething
。相反,在 Redux 应用程序中通常将所有操作定义放在一个名为 actionCreators.js
的单独文件中。这包含与您的操作同名的函数和 return 具有 type
属性 和操作所需的任何其他 methods/data 的对象。例如,这是一个非常简单的示例 actionCreators.js
文件:
export function getSomething() {
return {
type: 'GET_SOMETHING',
payload: {
something: 'Here is some data'
}
}
}
这个动作类型是你的 reducer 会监听的类型,以了解触发了哪个动作。
使用 mapStateToProps
反应组件:
import Item from './Item.jsx';
import { createStore } from 'redux';
import { getProduct, addProduct } from '../../actions';
import { connect } from "react-redux";
class Bundles extends React.Component {
constructor(props) {
super(props);
}
render() {
var productData = this.props.productData
return (
<div>
<span>
{
productData.map(item => (
<Item item={item} key={item.id} />
))
}
</span>
</div >
)
}
}
const mapStateToProps = (state) => {
// console.log(state.getProduct)
return {
productData: state.getProduct,
};
};
export default connect(mapStateToProps)(Bundles);
产品减速器
const productReducer = (state = data, action) => {
switch (action.type) {
case "GET_PRODUCT":
console.log(state)
return state
default:
return state;
}
}
export default productReducer;
RootReducer(所有减速器合并)
import getProduct from './products';
import getReviews from './reviews';
import { combineReducers } from 'redux';
const allReducers = combineReducers({
cartReducer, getProduct, getReviews
})
export default allReducers;
动作 (action/index.js)
// console.log('hahahahah')
return {
type: 'ADD_PRODUCT',
payload: n
}
}
也许我并没有全神贯注于 redux,但我看到的所有示例并没有真正在容器之间访问太多状态,所以我没有看到 store.getState() 的太多用法, 但即使你想发货,你也需要访问商店,对吗?
所以,除了导入 从 'path/to/store/store'
导入商店在我想要 getState() 或 "dispatch" 的每个文件中,我如何才能访问该状态,因为如果我不包含它,存储是未定义的。
如果您使用 react-redux
包,您将最终用 store
道具将组件包装在 Provider
中。这将在 React 上下文中设置您的单个商店,然后从子组件中的 connect
方法访问它。 connect
方法采用两个函数(mapStateToProps 和 mapDispatchToProps),它们是您从商店获取状态和发送消息的挂钩。
一般来说,您只想制作可以访问商店的顶级容器组件——它们会将任何必要的数据或动作分派作为道具传递给它们的子组件。这是 "smart" 和 "dumb" 组件之间的区别 - "smart" 组件了解 Redux store/state,而 "dumb" 组件只是将道具传递给它们并且不知道更大的应用程序状态。
然而,即使只是将存储传递给容器组件也会变得乏味。这就是 React-Redux 提供一个开箱即用的组件来包装整个应用程序的原因。 Check it out 在文档中。这是 Provider
组件,当你用它包装整个应用程序时,你只将商店传递给组件 once:
import createStore from '../store';
const store = createStore()
class App extends Component {
render() {
return (
<Provider store={store}>
<MainAppContainer />
</Provider>
)
}
}
正如您在此处看到的,我有一个单独的配置文件,仅适用于我的商店,因为您可以进行大量修改,对于任何远程复杂的应用程序,您会发现自己对诸如使用compose 应用中间件。
然后您剩余的任何 "smart" 组件(通常是包装器)都需要监听存储。这是使用 connect 方法完成的。这允许您将状态片段映射到您的组件属性以及将操作作为属性分派。
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as actionCreators from './actionCreators';
const mapStateToProps = function(state){
return {
something: state.something,
}
}
const mapDispatchToProps = function (dispatch) {
return bindActionCreators({
getSomething: actionCreators.getSomething,
}, dispatch)
}
class MainAppContainer extends Component {
componentDidMount() {
//now has access to data like this.props.something, which is from store
//now has access to dispatch actions like this.props.getSomething
}
render() {
//will pass down store data and dispatch actions to child components
return (
<div>
<ChildComponent1 something={this.props.something} />
<ChildComponent2 getSomething={this.props.getSomething} />
</div>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MainAppContainer)
因为您总是将调度操作和数据作为属性传递给您的子组件,所以您只需使用 this.props
.
基于上面的示例,您会看到因为我将 this.props.something
传递给 ChildComponent1
,它可以访问商店中的 something
数据,但它没有访问 getSomething
调度操作。同样,ChildComponent2
只能访问 getSomething
调度操作,但不能访问 something
数据。这意味着您只将组件公开给他们从商店中需要的东西。
例如,因为 ChildComponent2
作为 getSomething
传递给调度操作,在我的 onClick
中我可以调用 this.props.getSomething
并且它将调用调度操作 无需访问商店。以同样的方式它可以继续向下传递 getSomething
到另一个子组件并且该组件可以调用它 and/or 向下传递它并且循环可以无限期地继续。
class ChildComponent2 extends Component {
render() {
return (
<div>
<div onClick={this.props.getSomething}>Click me</div>
<NestedComponent getSomething={this.props.getSomething} />
</div>
)
}
}
根据评论编辑
虽然这与问题没有直接关系,但在评论中您似乎对操作有些困惑。我实际上并没有在这里定义动作 getSomething
。相反,在 Redux 应用程序中通常将所有操作定义放在一个名为 actionCreators.js
的单独文件中。这包含与您的操作同名的函数和 return 具有 type
属性 和操作所需的任何其他 methods/data 的对象。例如,这是一个非常简单的示例 actionCreators.js
文件:
export function getSomething() {
return {
type: 'GET_SOMETHING',
payload: {
something: 'Here is some data'
}
}
}
这个动作类型是你的 reducer 会监听的类型,以了解触发了哪个动作。
使用 mapStateToProps 反应组件:
import Item from './Item.jsx';
import { createStore } from 'redux';
import { getProduct, addProduct } from '../../actions';
import { connect } from "react-redux";
class Bundles extends React.Component {
constructor(props) {
super(props);
}
render() {
var productData = this.props.productData
return (
<div>
<span>
{
productData.map(item => (
<Item item={item} key={item.id} />
))
}
</span>
</div >
)
}
}
const mapStateToProps = (state) => {
// console.log(state.getProduct)
return {
productData: state.getProduct,
};
};
export default connect(mapStateToProps)(Bundles);
产品减速器
const productReducer = (state = data, action) => {
switch (action.type) {
case "GET_PRODUCT":
console.log(state)
return state
default:
return state;
}
}
export default productReducer;
RootReducer(所有减速器合并)
import getProduct from './products';
import getReviews from './reviews';
import { combineReducers } from 'redux';
const allReducers = combineReducers({
cartReducer, getProduct, getReviews
})
export default allReducers;
动作 (action/index.js)
// console.log('hahahahah')
return {
type: 'ADD_PRODUCT',
payload: n
}
}