React Contextによる状態管理(六)Contextによる通知効果

7426 ワード

Windowsシステムの右下にポップアップ通知、Macシステムの右上にポップアップ通知、iPhoneに上部通知、Androidに下部通知があることを知っています.Reactアプリでもこのような機能を実現したいなら、Contextが最適です.どうして似合うの?Contextの出現は共有状態管理を解決するためではないでしょうか.通知機能は、すべてのコンポーネントが共有する機能ではないでしょうか.各コンポーネントに通知コンポーネントを書くのは難しいですか?
一言も言わずにNotificationContextを作成します.
import React from 'react'

const { Provider, Consumer } = React.createContext()

class NotificationProvider extends React.Component {
    state = {
        messages: []
    }

    addMessage = text => {
        this.setState(state => ({
            messages: [
                ...state.messages,
                {
                    id: Math.random(),
                    text
                }
            ]
        }))
    }

    removeMessage = message => {
        this.setState(state => ({
            messages: state.messages.filter(msg => (
                msg.id !== message.id
            ))
        }))
    }

    render() {
        return (
            
                
    {this.state.messages.map(message => ( this.removeMessage(message)} > ))}
{this.props.children}
) } } const Notification = ({ message, onClose }) => (
  • {message.text}
  • )

    NotificationContextにはメッセージ・オブジェクトを格納するメッセージ・ステータス変数があり、addMessage関数は新しいメッセージを追加するために使用され、removeMessage関数はメッセージを削除するために使用されます.Notificationコンポーネントは、メッセージの内容と閉じるボタンを含むメッセージの表示をカプセル化するために使用されます.
    新しいニュースをシミュレートするためにhelperにいます.jsにgetLatestMessagesの関数を追加します.
    export function getLatestMessages() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(
                    Messages.map(msg => ({
                        ...msg,
                        id: Math.random()
                    })).slice(
                        0,
                        1
                    )
                );
            }, 1000);
        });
    }
    

    ここではsliceを用いて1つの情報のみを含む配列を取得する.
    では、MessageContext.を見てみましょう.js.
    componentDidMount() {
        this.setState({ loading: true, error: null })
        getMessages()
            .then(messages => this.setState({ loading: false, messages }))
            .catch(error => this.setState({ loading: false, error }))
        //       
        this.newMessageInterval = setInterval(this.newMessage, 5000)
    }
    

    すべてのメッセージを取得した後、5秒ごとに先ほどのhelperの新しいメッセージ生成関数を呼び出し、newMessage関数に論理をカプセル化しました.
    newMessage = () => {
            if (!this.state.loading) {
                getLatestMessages()
                    .then(message => {
                        this.setState(state => ({ messages: state.messages.concat(message) }))
                        this.props.notify(`      `)
                    })
            }
        }
    

    新しいメッセージがある場合は、既存のメッセージリストに追加し、通知を表示する関数notifyを呼び出します.notify関数は、MessageProviderコンポーネントに属性的に渡されるNotificationProviderのaddMessage関数です.しかし、ここでは、MetsageProviderに関数を渡すためにNotificationConsumerを使用するのではなく、高次コンポーネントを使用します.NotificationContextの最終コードは次のとおりです.
    import React from 'react'
    
    const { Provider, Consumer } = React.createContext()
    
    class NotificationProvider extends React.Component {
        state = {
            messages: []
        }
    
        addMessage = text => {
            this.setState(state => ({
                messages: [
                    ...state.messages,
                    {
                        id: Math.random(),
                        text,
                    }
                ]
            }))
        }
    
        removeMessage = message => {
            this.setState(state => ({
                messages: state.messages.filter(msg => (
                    msg.id !== message.id
                ))
            }))
        }
    
        render() {
            return (
                
                    
      {this.state.messages.map(message => ( this.removeMessage(message)} > ))}
    {this.props.children}
    ) } } const Notification = ({ message, onClose }) => (
  • {message.text}
  • ) // function withNotifier(Component) { return function Notified(props) { return ( { ({ notify }) => ( ) } ) } } export { NotificationProvider, Consumer as NotificationConsumer, withNotifier }

    MessageContextでwithNotifier関数をインポートすると、最終コードは次のようになります.
    import React from 'react'
    import { getMessages, getLatestMessages } from './helper'
    import { withNotifier } from './NotificationContext'
    
    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 }))
            this.newMessageInterval = setInterval(this.newMessage, 5000)
        }
    
        componentWillUnmount() {
            clearInterval(this.newMessage)
        }
    
        selectMessageHandler = (message) => {
            this.setState({ currentMessage: message })
        }
    
        newMessage = () => {
            if (!this.state.loading) {
                getLatestMessages()
                    .then(message => {
                        this.setState(state => ({ messages: state.messages.concat(message) }))
                        this.props.notify(`      `)
                    })
            }
        }
    
        render() {
            return (
                {this.props.children}
            )
        }
    }
    
    //         
    const MessageWithNotifierProvider = withNotifier(MessageProvider)
    export { MessageWithNotifierProvider as MessageProvider, Consumer as MessageConsumer }
    

    新しく追加された内容では、withNotify関数、MessageProviderをパラメータとして使用し、関数はnotifyプロパティ、すなわちNotifyプロパティを持つaddMessage関数をMessageProviderに渡すことを示します.
    最後にReactDOMでrender関数にルートコンポーネントとしてNotificationProviderコンポーネントを追加します.
    ReactDOM.render(
        
            
                
                    
                
            
        ,
        document.getElementById('root')
    );
    

    これで、グローバル通知機能付きのAppが完了します.