订阅Redux商店中的单一房产变更

kar*_*ski 50 react-native redux-framework redux

在Redux中,我可以轻松订阅商店更改

store.subscribe(() => my handler goes here)
Run Code Online (Sandbox Code Playgroud)

但是,如果我的商店充满了不同的对象,并且在我的应用程序中的某个特定位置,我想订阅仅在商店中的特定对象中进行的更改?

And*_*ker 93

subscribe直接使用时无法订阅商店的一部分,但正如Redux的创建者所说 - 不要subscribe直接使用!为了使Redux应用程序的数据流真正起作用,您需要一个包装整个应用程序的组件.该组件将订阅您的商店.其余的组件将成为此包装器组件的子组件,并且只能获取所需的状态部分.

如果您使用Redux和React,那么有一个好消息 - 官方的react-redux软件包会为您解决这个问题!它提供了包装器组件,称为<Provider />.然后,您将拥有至少一个"智能组件",用于侦听Provider商店传递的状态更改.您可以指定它应该监听的状态的哪些部分,并且状态的那些部分将作为道具传递给该组件(当然,它可以将这些部分传递给它自己的子组件).您可以通过使用"智能"组件上的connect()函数并将该mapStateToProps函数用作第一个参数来指定它.回顾一下:

使用Provider订阅存储更改的组件包装根组件

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)
Run Code Online (Sandbox Code Playgroud)

现在的任何一个孩子<App />被包裹connect()将是一个"聪明"的组成部分.您可以传入mapStateToProps以选择州的某些部分并将其作为道具.

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

class ChildOfApp extends Component {
    render() {
        return <div>{this.props.somethingFromStore}</div>
    }
}

//wrap App in connect and pass in mapStateToProps
export default connect(mapStateToProps)(ChildOfApp)
Run Code Online (Sandbox Code Playgroud)

显然<App />可以有很多孩子,你可以挑选和选择mapStateToProps每个孩子应该听哪个州的部分.我建议阅读有关使用React的文档,以便更好地理解这个流程.


mar*_*son 14

Redux只提供一种通用方法来了解商店何时更新:subscribe方法.回调subscribe没有得到任何可能已经改变的信息,因为subscribeAPI故意是低级别的,并且只是在没有参数的情况下运行每个回调.所有你知道的是商店已经以某种方式更新.

因此,有人必须编写特定的逻辑来比较旧状态与新状态,并查看是否有任何变化.您可以使用React-Redux处理此问题,mapStateToProps为组件指定一个函数,在组件中实现componentWillReceiveProps,并检查商店中的特定道具是否已更改.

还有一些试图处理这种情况的插件库:https://github.com/ashaffer/redux-subscribehttps://github.com/jprichardson/redux-watch.两者基本上都允许您使用不同的方法指定要查看的状态的特定部分.


小智 5

创建了一个技巧来帮助了解可以根据商店数据区分订阅者,并具有多个商店功能。

//import { createStore } from 'redux';
let createStore = require('redux').createStore;
let combineReducers = require('redux').combineReducers;
/**
 * This is a reducer, a pure function with (state, action) => state signature.
 * It describes how an action transforms the state into the next state.
 *
 * The shape of the state is up to you: it can be a primitive, an array, an object,
 * or even an Immutable.js data structure. The only important part is that you should
 * not mutate the state object, but return a new object if the state changes.
 *
 * In this example, we use a `switch` statement and strings, but you can use a helper that
 * follows a different convention (such as function maps) if it makes sense for your
 * project.
 */
function counter(state = 0, action) {
    switch (action.type) {
        case 'INCREMENT':
            return state + 1
        case 'DECREMENT':
            return state - 1
        default:
            return state
    }
}

function messanger(state = 'Mr, khazi', action) {
    switch(action.type) {
        case 'WELCOME':
            return 'Hello, Mr Khazi';
        case 'BYE':
            return 'Bye, Mr Khazi';
        case 'INCREMENT':
            return 'Incremented khazi';
        default:
            return state;
    }
};

function latestAction(state = null, action) {
    switch(action.type) {
        case 'WELCOME':
            return '$messanger';
        case 'BYE':
            return '$messanger';
        case 'INCREMENT':
            return '$messanger, $counter';
        case 'DECREMENT':
            return '$counter';
        default:
            return state;
    }
};

let reducers = {
    counts: counter,
    message: messanger,
    action: latestAction
};

let store = createStore(
    combineReducers(reducers, latestAction)
);
  
// Create a Redux store holding the state of your app.
// Its API is { subscribe, dispatch, getState }.
//let store = createStore(counter)

// You can use subscribe() to update the UI in response to state changes.
// Normally you'd use a view binding library (e.g. React Redux) rather than subscribe() directly.
// However it can also be handy to persist the current state in the localStorage.
store.subscribe(() => {
    if(store.getState().action.indexOf('messanger') !== -1) {
        console.log('subscribed for counter actions', store.getState());
    }
});

store.subscribe(() => {
    if (store.getState().action.indexOf('counter') !== -1) {
        console.log('subscribed for messanger actions', store.getState());
    }
});

// The only way to mutate the internal state is to dispatch an action.
// The actions can be serialized, logged or stored and later replayed.
console.log('----------------Action with both subscriber-------------');
store.dispatch({ type: 'INCREMENT' });
console.log('---------------Action with counter subscriber-----------');
store.dispatch({ type: 'DECREMENT' });
console.log('---------------Action with messenger subscriber---------');
store.dispatch({ type: 'WELCOME' });

/*
    every reducer will execute on each action.

*/
Run Code Online (Sandbox Code Playgroud)