Redux访问mapStateToProps中对象列表中的正确项

时间:2017-01-02 22:48:08

标签: javascript reactjs redux

这是我遇到的问题。我必须将id={this.props.id}传递给每个组件,这样我才能通过查看ownProps从mapStateToProps中的玩家列表中获取正确的玩家。

  1. 这些AudioPlayer组件将由开发人员提供,因此我不希望他们必须像我目前所做的那样将id传递给每个组件。
  2. 我不能只使用React的上下文,因为mapStateToProps由于它是实验性的而不会公开上下文。
  3. 我知道我可以在每个组件(GUI,媒体等)中执行React.CloneElement,但这似乎也是如此。
  4. 我的问题是

    如何从列表中获取正确的播放器,而无需将ID传递给我的每个组件,如下面的代码所示?

    如果mapStateToProps接受context param,那么我可以从每个组件的上下文中获取id并将其传递一次。

    他们是更好的方法吗?

    开发人员定义的AudioPlayers:

    class AudioPlayer extends React.Component {
        render() {
            return (
                <Player className="jp-default" id={this.props.id}>
                    <Gui id={this.props.id}>
                        <Media id={this.props.id}>
                            <Audio id={this.props.id}>                           
                            </Audio>
                        </Media>
                        <div className="poster-container">
                            <Poster id={this.props.id}/>
                            <Title id={this.props.id}/>
                        </div>
                    </Gui>             
                </Player>
            );
        }
    }
    
    AudioPlayer.options = {
        id: "audio-player",
        paused: true,
        //...etc
    };
    
    class AudioPlayerTwo extends React.Component {
        render() {
            return (
                <Player className="jp-default-two" id={this.props.id}>
                    <Gui id={this.props.id}>
                        <Media id={this.props.id}>
                            <Audio id={this.props.id}>                        
                            </Audio>
                        </Media>
                        <div className="poster-container">
                            <Poster id={this.props.id}/>
                            <Title id={this.props.id}/>
                        </div>
                    </Gui>             
                </Player>
            );
        }
    }
    
    AudioPlayerTwo.options = {
        id: "audio-player-two,
        paused: true,
        //...etc
    };
    
    createPlayers([AudioPlayer, AudioPlayerTwo]);
    

    将成为npm包的代码:

    export createPlayers (WrappedPlayers) => {
        const store = createStore(combineReducers({players: playerReducer}));
    
        ReactDOM.render(
        <Provider store={store}>
            <div>
                {WrappedPlayers.map(WrappedPlayer => {
                    const ConnectedPlayer = connect(mapStateToProps, mapDispatchToProps)(WrappedPlayer);
    
                    <ConnectedPlayer key={WrappedPlayer.options.id} id={WrappedPlayer.options.id} />
                })}
            </div>
        </Provider>,
        document.getElementById("app"));
    }
    

    动作:

    export const play = (id, time) => ({
        type: actionTypes.player.PLAY,
        time,
        id
    });
    ...etc
    

    减速器:

    const play = (state, action) => {
        if(state.srcSet) {
            return updateObject(state, {
                paused: false,
                newTime: !isNaN(action.time) ? action.time : state.currentTime 
            });
        }
    }
    
    export default (state={}, action) => {
        //Only update the correct player
        const currentPlayer = state[action.id];
        let newState = {...state};
    
        switch (action.type) {; 
            case actionTypes.player.PLAY: 
                newState = play(currentPlayer, action);
                break;
            default:
                return state;
        }
    
        return updateObject(state, {
            [action.id]: newState
        });
    }
    

    我的所有组件都与此类似: 请注意我如何使用道具id从列表中访问正确的播放器。

    const mapStateToProps = (state, props) => ({
        paused: state.players[props.id].paused,
        id: props.id
    });
    
    const Play = (props) => {
        const onPlayClick = () => props.paused ? props.dispatch(play(props.id)) : props.dispatch(pause(props.id))
        return <a onClick={onPlayClick}>{props.children}</a>
    }
    
    export default connect(mapStateToProps)(Play);
    

1 个答案:

答案 0 :(得分:4)

您可以通过在connect + getContext(来自recompose)上创建自己的包装来在userland中解决此问题,并在您的应用中使用它而不是vanilla connect。它看起来像

import { connect } from 'react-redux'
import { compose, getContext } from 'recompose'
export default function connectWithMyId(...args) {
  return compose(
    getContext({ myId: PropTypes.string }),
    connect(...args)
  )
}

然后myIdmapStateToProps作为道具提供。{/ 1}}。