简体   繁体   English

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

[英]Redux Accessing correct item in object list in mapStateToProps

Here is the problem I am having. 这是我遇到的问题。 I have to pass id={this.props.id} to each component so that I can get the correct player from the list of players in mapStateToProps by looking at ownProps. 我必须将id={this.props.id}传递给每个组件,以便可以通过查看ownProps从mapStateToProps的播放器列表中获取正确的播放器。

  1. These AudioPlayer components are going to be provided by the developer so I don't want them having to pass in the id like I am doing currently to every component. 这些AudioPlayer组件将由开发人员提供,因此我不希望它们像我当前正在传递给每个组件那样传递id。
  2. I can't just use React's context because mapStateToProps doesn't expose the context due to it being experimental. 我不能只使用React的上下文,因为mapStateToProps由于处于实验状态而不会公开该上下文。
  3. I know I can just do React.CloneElement in each of the components (GUI, Media etc) but this seems meh as well. 我知道我可以在每个组件(GUI,媒体等)中执行React.CloneElement,但这似乎也很不错。

My question is : 我的问题是

How can I get the correct player out of the list without having to pass the id to each of my components like in the code below? 我如何从列表中剔除正确的播放器,而不必像下面的代码那样将ID传递给我的每个组件?

If mapStateToProps accepted a context param then I could just get the id from the context in each of the components and pass it down once. 如果mapStateToProps接受了context参数,那么我可以从每个组件的上下文中获取ID并将其向下传递一次。

Is their a better way of doing this? 他们是这样做的更好方法吗?

AudioPlayers that the developer defines: 开发人员定义的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]);

Code that is going to be an npm package: 将成为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"));
}

actions: 动作:

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

reducer: 减速器:

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
    });
}

All of my components look similar to this: Notice how I access the correct player from the list with the props id . 我所有的组件看起来都与此类似:注意如何从列表中使用props 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);

You can solve this in userland by making your own wrapper on connect + getContext (from recompose ) and use that in your app instead of vanilla connect. 您可以通过在connect + getContext (来自recompose )上创建自己的包装,并在应用程序中使用它而不是普通的connect来在用户领域解决此问题。 It'd look something like 看起来像

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

And then myId would be available as a prop in your mapStateToProps . 然后, myId就可以作为你的一个道具mapStateToProps

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM