具有内部隔离 Redux 存储的可重用组件
Resuable component with internal, isolated Redux store
我正在考虑在 React 中构建一个非常复杂的图表组件,我希望它可以在许多不同的项目中使用。不用说,像这样的组件有多种状态需要以某种方式进行管理。
Redux 似乎非常适合这个,但是如果我只是将顶级容器包装在带有自定义存储的 Provider 中...如果组件的内部 redux 存储不会干扰全局应用程序状态包含在更大的 React/Redux 应用程序中?
import React, { Component } from 'react';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import internalReducer from './reducer';
export default class MyReduxComponent extends Component {
render() {
const store = createStore(internalReducer, this.props.initialState);
return <Provider store={store}>
<Chart />
</Provider>
}
}
你的组件不应该有自己的内部 redux store,而是有自己的 reducer + reducer 知道的动作/动作创建者,这样它就可以很容易地与现有的 redux 应用程序集成:
import { chartReducer, chartActionCreators } from 'your-chart'
combineReducers({
...global.stuff,
chartReducer
})
store.dispatch(chartActionCreators.action())
--
import Chart from 'your-chart'
export default () =>
<div>
<Chart />
</div>
您的库的用户可能不需要显式使用任何操作,只需包含 reducer 就足够了,因此可以在应用程序的任何位置访问图表状态。
此外,如果您需要以某种方式增强您的操作调用,您可以编写一些中间件。
你有没有仅仅使用 React 组件状态的原因? Redux 旨在用于需要由整个应用程序中的多个组件访问的状态。如果您管理的状态仅供特定组件的后代使用,那么您也可以只使用组件状态——在这种情况下不需要 Redux。这样您的组件将更加可重用,并且不会依赖其他依赖项。
我想我找到了一个很好的解决问题的方法,在顶部组件中使用 childContextTypes
和 setState
。这允许任何深度的子组件仅 "import" 他们需要的上下文操作。 (这消除了通过多个嵌套组件将回调作为 props 传递下去的需要)。
顶级组件可能如下所示
export default class ReusableComponent extends Component {
// Define the public API interface to child components
static childContextTypes = {
// expose component state store
store: PropTypes.object,
// actions
setFoo: PropTypes.func,
setBar: PropTypes.func
};
// Set initial state, can be overriden by props
constructor(props) {
super(props)
this.state = {
foo: 'My Foo',
...props
}
}
// Define methods for public API
getChildContext() {
return {
store: this.state,
setFoo: this.setFoo.bind(this),
setBar: this.setBar.bind(this)
};
}
// Reducer for action setFoo
setFoo(foo) {
this.setState({ foo })
}
// Just render components, no need for passing props
render() {
return <div>
<UpdateFooComponent />
</div>
}
}
还有一个子组件
class UpdateFooComponent extends Component {
// 'import' the store and actions you need from top component
static contextTypes = {
store: PropTypes.object,
setFoo: PropTypes.func
};
clickHandler(e) {
this.context.setFoo('Hello from subcomponent');
}
render() {
const { foo } = this.context.store;
return <div>
<button onClick={::this.clickHandler}>Update foo</button>
<p><strong>foo:</strong> {foo}</p>
</div>
}
}
我正在考虑在 React 中构建一个非常复杂的图表组件,我希望它可以在许多不同的项目中使用。不用说,像这样的组件有多种状态需要以某种方式进行管理。
Redux 似乎非常适合这个,但是如果我只是将顶级容器包装在带有自定义存储的 Provider 中...如果组件的内部 redux 存储不会干扰全局应用程序状态包含在更大的 React/Redux 应用程序中?
import React, { Component } from 'react';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import internalReducer from './reducer';
export default class MyReduxComponent extends Component {
render() {
const store = createStore(internalReducer, this.props.initialState);
return <Provider store={store}>
<Chart />
</Provider>
}
}
你的组件不应该有自己的内部 redux store,而是有自己的 reducer + reducer 知道的动作/动作创建者,这样它就可以很容易地与现有的 redux 应用程序集成:
import { chartReducer, chartActionCreators } from 'your-chart'
combineReducers({
...global.stuff,
chartReducer
})
store.dispatch(chartActionCreators.action())
--
import Chart from 'your-chart'
export default () =>
<div>
<Chart />
</div>
您的库的用户可能不需要显式使用任何操作,只需包含 reducer 就足够了,因此可以在应用程序的任何位置访问图表状态。
此外,如果您需要以某种方式增强您的操作调用,您可以编写一些中间件。
你有没有仅仅使用 React 组件状态的原因? Redux 旨在用于需要由整个应用程序中的多个组件访问的状态。如果您管理的状态仅供特定组件的后代使用,那么您也可以只使用组件状态——在这种情况下不需要 Redux。这样您的组件将更加可重用,并且不会依赖其他依赖项。
我想我找到了一个很好的解决问题的方法,在顶部组件中使用 childContextTypes
和 setState
。这允许任何深度的子组件仅 "import" 他们需要的上下文操作。 (这消除了通过多个嵌套组件将回调作为 props 传递下去的需要)。
顶级组件可能如下所示
export default class ReusableComponent extends Component {
// Define the public API interface to child components
static childContextTypes = {
// expose component state store
store: PropTypes.object,
// actions
setFoo: PropTypes.func,
setBar: PropTypes.func
};
// Set initial state, can be overriden by props
constructor(props) {
super(props)
this.state = {
foo: 'My Foo',
...props
}
}
// Define methods for public API
getChildContext() {
return {
store: this.state,
setFoo: this.setFoo.bind(this),
setBar: this.setBar.bind(this)
};
}
// Reducer for action setFoo
setFoo(foo) {
this.setState({ foo })
}
// Just render components, no need for passing props
render() {
return <div>
<UpdateFooComponent />
</div>
}
}
还有一个子组件
class UpdateFooComponent extends Component {
// 'import' the store and actions you need from top component
static contextTypes = {
store: PropTypes.object,
setFoo: PropTypes.func
};
clickHandler(e) {
this.context.setFoo('Hello from subcomponent');
}
render() {
const { foo } = this.context.store;
return <div>
<button onClick={::this.clickHandler}>Update foo</button>
<p><strong>foo:</strong> {foo}</p>
</div>
}
}