首先确认一点,Context是可以嵌套使用的,因为Context也是Component,当然可以嵌套。
创建MessageContext.js,也就是共享Message相关的变量和函数。代码如下:
const { Provider, Consumer } = React.createContext()
class MessageProvider extends React.Component {
state = {
messages: [],
currentMessage: null,
error: null,
loading: false
}
componentDidMount() {
this.setState({ loading: true, error: null })
getMessages()
.then(messages => this.setState({ loading: false, messages }))
.catch(error => this.setState({ loading: false, error }))
}
selectMessageHandler = (message) => {
this.setState({ currentMessage: message })
}
render() {
return (
<Provider value={{
...this.state,
onSelectMessage: this.selectMessageHandler
}}>{this.props.children}</Provider>
)
}
}
export { MessageProvider, Consumer as MessageConsumer }
没什么可讲的,getMessages函数是helper.js里新加的内容,用来模拟api调用的,代码如下:
export const Messages = [
{
id: 0,
subject: 'Message1',
body: 'Message1'
},
{
id: 1,
subject: 'Message2',
body: 'Message2'
},
{
id: 2,
subject: 'Message3',
body: 'Message3'
}
]
export function getMessages() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(Messages)
}, 1000);
})
}
在ReactDom.render函数中,我们来使用新创建的MessageProvider,作为UserProvider的子组件:
ReactDOM.render(
<UserProvider>
<MessageProvider>
<App />
</MessageProvider>
</UserProvider>,
document.getElementById('root')
);
然后我们一边来补充完成应用,一边来使用MessageConsumer。
添加Message组件,作为MessageList的子组件。代码如下:
const Message = ({ message, onClick }) => (
<li onClick={onClick}>
<div>{message.subject}</div>
</li>
)
Message组件会显示信息标题,我们这里就直接传入整个message了;有onClick属性,即点击该条message会显示具体内容。
添加MessageDetails组件,即显示message的具体内容,这里使用了MessageConsumer,代码如下:
const MessageDetails = () => (
<MessageConsumer>
{({ currentMessage, onSelectMessage }) => (
<div>
<button onClick={() => onSelectMessage(null)}>
Back
</button>
<h3>{currentMessage.subject}</h3>
<div>{currentMessage.body}</div>
</div>
)}
</MessageConsumer>
)
最后看下MessageList组件:
<UserConsumer>
{
({ user }) => (
<MessageConsumer>
{
({ loading, messages, onSelectMessage }) => (
<div>
{
loading ? <div>加载中......</div> :
messages.length === 0 ? <div>没有信息, {user.name}</div> :
<ul>
{messages.map(message => <Message key={message.id} message={message} onClick={() => onSelectMessage(message)} />)}
</ul>
}
</div>
)
}
</MessageConsumer>
)
}
</UserConsumer>
这里我们看到了Consumer的嵌套使用,Consumer的嵌套看起来更像函数闭包的应用,因为Consumer包裹的是个函数,子Consumer被包裹在父Consumer的函数里,并使用了父Consumer函数中的变量user。其他的没啥可说的,解构对象,给组件属性赋值等等。
下一次我们看看Context的Provider和Consumer的配对使用问题。
网友评论