Reactの子コンポーネントから親コンポーネントへのコールバック関数

0
Vova 2020-03-30 20:45.

チャットしようとしています。しかし、メッセージを送信するときは、ページのデータを取得するためにページを更新する必要があります。FormsとSendMsgをコンポーネント化する必要があります。

親:

...
import client from '../Utils/Contentful';

export default class Forms extends Component {
    constructor() {
        super()
        this.state = {
            messages: [],
        }
    } 

    componentDidMount(){
        client.getEntries({limit:300, order: 'sys.createdAt', content_type:'nameTest'}).then(response => {
            this.setState({messages: response.items});
        }).catch(e => {
          console.log(e);
        });
    }
render() {
        return (
            <div className="chat">
                <div className="container-xl">
                    <MessageList messages={this.state.messages}/>
                    <SendMsg />
                </div>
            </div>
        );
    }
}

そして子コンポーネント

...
import client from '../Utils/ContentfulCM';

export default class SendMsg extends Component {
    constructor() {
        super()
        this.state = {
            message:'',
            userEmail:'[email protected]',
            chatName:'ggg'
        }
        this.sendMessage = this.sendMessage.bind(this)
        this.handleChange = this.handleChange.bind(this)

    } 

    handleChange(e) {
        this.setState({
            message: e.target.value,
        })
    }

    sendMessage(e) {
        e.preventDefault();

        const form = e.target;
        const data = new FormData(form);

        client.getSpace(client.space)
        .then((space) => space.getEnvironment('master'))
        .then((environment) => environment.createEntry('nameTest', {
            fields: {
                chatName: {
                    'en-US': data.get('chatName')
                },
                //... some data
            }
        }))
        .then((entry) => entry.publish())
        .catch(console.error)

        this.setState({
            message: ''
        })
    }

    render() {
        return (
            <div className="send-message">
                <Form className="send-msg" onSubmit={this.sendMessage}>
                    <FormGroup>
                        <Input type="hidden" name="userEmail" value={this.state.userEmail}/>    
                    </FormGroup>
                    <FormGroup>
                        <Input type="hidden" name="chatName" value={this.state.chatName}/>    
                    </FormGroup>

                    <FormGroup>
                        <Input 
                            type="text" 
                            name="text"
                            onChange={this.handleChange}
                            value={this.state.message}
                            placeholder="Write your message here"
                            required />
                    </FormGroup>
                    <FormGroup>
                        <Input type="hidden" name="dateCreated" value={moment().format()} onChange={this.handleChange}/>    
                    </FormGroup>
                </Form>
            </div>
        );
    }
}

小道具を追加しようとしましたが、適切な場所がわかりません。何か提案はありますか?

アップデート1

両方のコンポーネントに「インポートクライアント」があり(uniq accessTokenがあるため、これらは異なります)、そのため、1つのコンポーネントでそれらを使用することはできません。

アップデート2

以下の提案に従って質問を変更しましたが、表示されたデータを取得するにはページを更新する必要があります。

親:

export default class Forms extends Component {
    constructor() {
        super()
        this.state = {
            messages: [],
        }
        this.sendMessage = this.sendMessage.bind(this);
    } 

    componentDidMount(){
        client1.getEntries({limit:300, order: 'sys.createdAt', content_type:'nameTest'}).then(response => {
            this.setState({messages: response.items});
        }).catch(e => {
          console.log(e);
        });
    }
sendMessage(data) {
        client2.getSpace(client2.space)
        .then((space) => space.getEnvironment('master'))
        .then((environment) => environment.createEntry('nameTest', {
            fields: {
                chatName: {
                    'en-US': data.get('chatName')
                ... some data
            }
        }))
        .then((entry) => entry.publish())
        .catch(console.error)
    }
render() {
        return (
            <div className="chat">
                <div className="container-xl">
                    <MessageList messages={this.state.messages}/>
                    <SendMsg onSendMessage={this.sendMessage}/>
                </div>
            </div>
        );
    }
}

そして子コンポーネント


export default class SendMsg extends Component {
    constructor() {
        super()
        this.state = {
            message:'',
            userEmail:'[email protected]',
            chatName:'ggg'
        }
        this.sendMessage = this.sendMessage.bind(this)
        this.handleChange = this.handleChange.bind(this)

    } 

    handleChange(e) {
        this.setState({
            message: e.target.value,
        })
    }

    sendMessage(e) {
        e.preventDefault();

        const { onSendMessage } = this.props;

        const form = e.target;
        const data = new FormData(form);

        // if send message handler was passed, invoke with form data
        onSendMessage && onSendMessage(data);

        this.setState({
            message: ''
        })
    }

    render() {
        return (
            <div className="send-message">
                <Form className="send-msg" onSubmit={this.sendMessage}>
                    <FormGroup>
                        <Input type="hidden" name="userEmail" value={this.state.userEmail}/>    
                    </FormGroup>
                    <FormGroup>
                        <Input type="hidden" name="chatName" value={this.state.chatName}/>    
                    </FormGroup>

                    <FormGroup>
                        <Input 
                            type="text" 
                            name="text"
                            onChange={this.handleChange}
                            value={this.state.message}
                            placeholder="Write your message here"
                            required />
                    </FormGroup>
                    <FormGroup>
                        <Input type="hidden" name="dateCreated" value={moment().format()} onChange={this.handleChange}/>    
                    </FormGroup>
                </Form>
            </div>
        );
    }
}

2 answers

2
Drew Reese 2020-03-30 21:03.

親でコールバックを定義します。子のフォームからメッセージデータを抽出して送信するロジックを分割します。親のコールバックはメッセージデータを受信して​​送信し、子コンポーネントの関数はフォームデータをプルしてフォーマットし、propsで渡されたコールバックを呼び出し、入力フィールドをクリアします。

export default class Forms extends Component {
    constructor() {
        super()
        this.state = {
            messages: [],
        }
        this.sendMessage = this.sendMessage.bind(this);
    } 

    componentDidMount(){
        client.getEntries({limit:300, order: 'sys.createdAt', content_type:'nameTest'}).then(response => {
            this.setState({messages: response.items});
        }).catch(e => {
          console.log(e);
        });
    }

    sendMessage(data) {
        client.getSpace(client.space)
        .then((space) => space.getEnvironment('master'))
        .then((environment) => environment.createEntry('nameTest', {
            fields: {
                chatName: {
                    'en-US': data.get('chatName')
                },
                //... some data
            }
        }))
        .then((entry) => entry.publish())
        .catch(console.error);
    }

    render() {
        return (
            <div className="chat">
                <div className="container-xl">
                    <MessageList messages={this.state.messages}/>
                    <SendMsg onSendMessage={sendMessage} />
                </div>
            </div>
        );
    }
}

export default class SendMsg extends Component {
    constructor() {
        super()
        this.state = {
            message:'',
            userEmail:'[email protected]',
            chatName:'ggg'
        }
        this.sendMessage = this.sendMessage.bind(this)
        this.handleChange = this.handleChange.bind(this)

    } 

    handleChange(e) {
        this.setState({
            message: e.target.value,
        })
    }

    sendMessage(e) {
        e.preventDefault();

        const { onSendMessage } = this.props;

        const form = e.target;
        const data = new FormData(form);

        // if send message handler was passed, invoke with form data
        onSendMessage && onSendMessage(data);

        this.setState({
            message: ''
        });
    }

    render() {
        return (
            <div className="send-message">
                <Form className="send-msg" onSubmit={this.sendMessage}>
                    <FormGroup>
                        <Input type="hidden" name="userEmail" value={this.state.userEmail}/>    
                    </FormGroup>
                    <FormGroup>
                        <Input type="hidden" name="chatName" value={this.state.chatName}/>    
                    </FormGroup>

                    <FormGroup>
                        <Input 
                            type="text" 
                            name="text"
                            onChange={this.handleChange}
                            value={this.state.message}
                            placeholder="Write your message here"
                            required />
                    </FormGroup>
                    <FormGroup>
                        <Input type="hidden" name="dateCreated" value={moment().format()} onChange={this.handleChange}/>    
                    </FormGroup>
                </Form>
            </div>
        );
    }
}

同期機能を含むように更新

同期API

Javascirptでの同期APIの使用

親コンポーネントの更新:

  • インターバルタイマー参照を保持するクラスインスタンスタイマー変数を追加します
  • 同期データ呼び出しを処理する関数を作成する
  • componentDidMountコンポーネントのマウント時に初期データを同期するように更新し、データ同期ポーリングを設定します(これはイベント駆動型ではないため
  • componentWillUnmountライフサイクル機能にタイマークリーンアップを追加

constructor() {
  super()
  this.state = {
    messages: [],
  }
  this.syncTimer = null;

  this.sendMessage = this.sendMessage.bind(this);
}

initialSyncClient = () => client1.sync({
  initial: true
  limit:100,
  order: 'sys.createdAt',
  content_type: 'nameTest',
});

syncClient = () => {
  const { nextSyncToken } = this.state;
  client1.sync({
    nextSyncToken
  })
    .then(this.handleSyncResponse)
    .catch(e => {
      console.log(e);
    });
};

handleSyncResponse = ({ entries, nextSyncToken}) => {
  // response shape is a little different, 
  // response.entries vs. response.items, so need to access correctly
  // also need to save nextSyncToken for all subsequent syncs
  this.setState({
    messages: entries.items,
    nextSyncToken,
  });
};

componentDidMount(){
  // do initial sync
  this.initialSyncClient()
    .then(this.handleSyncResponse)
    .catch(e => {
      console.log(e);
    });

  // setup sync polling, 15 second interval
  this.syncTimer = setInterval(syncClient, 15 * 1000);
}

componentWillUnmount() {
  // clean up polling timer when component unmounts
  clearInterval(this.syncTimer);
}

注:これらの変更は純粋にcontentfulドキュメントに基づいているため、期待どおりに機能させるために、または矢印関数などを使用したくない場合は、微調整が必​​要になる場合があります...

0
pawelek91 2020-03-30 20:54.

関数sendMessageを親に追加しようとしている場所がわかりません。

小道具で提供できますが、そうではありません。

子コンポーネントでは、次のようなことができます

interface IChildComponentWithSendMessage{
    sendMessage
}

export class ChildComponent extends React.Component<IChildComponentWithSendMessage>

そしてあなたは小道具によってあなたにmessageMethodを提供することができます

また、あなたはする必要はありません

   this.sendMessage = this.sendMessage.bind(this)

また、このメソッドを子/親コンポーネントに提供できない理由が問題になる可能性があると思います

次のような関数を作成できます。

sendMessage = () => {
}

Related questions

MORE COOL STUFF

Reba McEntire は、彼女が息子の Shelby Blackstock と共有する「楽しい」クリスマスの伝統を明らかにしました:「私たちはたくさん笑います」

Reba McEntire は、彼女が息子の Shelby Blackstock と共有する「楽しい」クリスマスの伝統を明らかにしました:「私たちはたくさん笑います」

Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。

メーガン・マークルは、自然な髪のスタイリングをめぐってマライア・キャリーと結ばれました

メーガン・マークルは、自然な髪のスタイリングをめぐってマライア・キャリーと結ばれました

メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.

ハリー王子は家族との関係を修復できるという「希望を持っている」:「彼は父親と兄弟を愛している」

ハリー王子は家族との関係を修復できるという「希望を持っている」:「彼は父親と兄弟を愛している」

ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。

ワイノナ・ジャッドは、パニックに陥った休暇の瞬間に、彼女がジャッド家の家長であることを認識しました

ワイノナ・ジャッドは、パニックに陥った休暇の瞬間に、彼女がジャッド家の家長であることを認識しました

ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

iOS9でSiriに尋ねることができるすべての新しいもの

iOS9でSiriに尋ねることができるすべての新しいもの

AppleがiOS9を発表したときの大きな話題の1つは、Siriがどのように改善され、より「プロアクティブ」になるかということでした。最初はそれが何を意味するのか実際にはわかりませんでしたが、iOSが1週間使用されたので、iOSに何を依頼できるかについてはるかに良いアイデアが得られました。

「食料品の請求書はあなたが絶対に管理できるものの1つです」

「食料品の請求書はあなたが絶対に管理できるものの1つです」

非常に多くのサービスと生活費には、たまにしか変わらない設定価格があります。ただし、食料品の請求書は、閉じ込められておらず、完全に管理できる唯一の場所の1つです。

デスティニーのエキゾチックな戦利品ドロップで何か奇妙な

デスティニーのエキゾチックな戦利品ドロップで何か奇妙な

Destinyにとって興味深い週末でした。新しいエクスプロイトのおかげで、プレイヤーはゲームの戦利品システムがどのように機能するかを通常よりも詳しく見ることができました。

Destinyの最新のエクスプロイトでエキゾチックな自分を殺すことができます[更新:パッチ]

Destinyの最新のエクスプロイトでエキゾチックな自分を殺すことができます[更新:パッチ]

今日Destinyをプレイし始めた場合、同じ古代の低レベルのミッションを実行している友人の数が異常に多いことに気付いたかもしれません。なぜ彼らはそうするのでしょうか?答えは-もちろんこれが答えです-ミッションはプレイヤーが新しい抜け穴を利用し、最小限の労力でたくさんの強力なエキゾチックなアイテムを獲得できるようにすることです。

アマゾンの買い物客はこれを「ホテル品質」の羽毛布団カバーと呼んでおり、価格はわずか22ドルです

アマゾンの買い物客はこれを「ホテル品質」の羽毛布団カバーと呼んでおり、価格はわずか22ドルです

何千人もの Amazon の買い物客が Bedsure Duvet Cover を推奨しており、現在セール中です。羽毛布団カバーにはいくつかの色があり、ツインからカリフォルニアキングまでのサイズがあります。Amazon で最大 52% オフの最高評価の羽毛布団カバーを購入する

バレンタインデーにユーカリのシャワースチーマーで「最高の睡眠」を贈りましょう。

バレンタインデーにユーカリのシャワースチーマーで「最高の睡眠」を贈りましょう。

BodyRestore ユーカリ シャワー スチーマーは、Amazon で 11,000 を超える 5 つ星の評価を得ています。セルフケアが必要な人へのバレンタインデーのギフトとして、ホームスパ製品を贈りましょう。

この「邪悪な吸引力」を備えたこの250ドルのハンドヘルド掃除機は、Amazonで75%オフになりました

この「邪悪な吸引力」を備えたこの250ドルのハンドヘルド掃除機は、Amazonで75%オフになりました

多くのAmazonの買い物客がUmlo H6ハンドヘルド掃除機を推奨しており、現在スーパーセール中です. ハンドヘルド デバイスには HEPA フィルターが装備されており、複数のアタッチメントが付属しています。Amazonで75%オフのときにハンドヘルド掃除機を購入する

オクタヴィア・スペンサー、「ザ・ヘルプ」共演者のシシー・スペイセクが17歳で映画のインターンをした後、彼女のことを「実際に」思い出したと語る

オクタヴィア・スペンサー、「ザ・ヘルプ」共演者のシシー・スペイセクが17歳で映画のインターンをした後、彼女のことを「実際に」思い出したと語る

オクタヴィア・スペンサーは、ヘルプで一緒に共演するずっと前に、シシー・スペイセク主演の 1990 年の映画「ロング・ウォーク・ホーム」でインターンとして働いていました。

メリック・ガーランドはアメリカに失敗しましたか?

バイデン大統領の任期の半分以上です。メリック・ガーランドは何を待っていますか?

メリック・ガーランドはアメリカに失敗しましたか?

人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。

良いものと醜いもの: 2022

良いものと醜いもの: 2022

もうわからない。何が「ヒット」かを正確に判断することは、もはやほとんど不可能に思えます。

楽しみのために — 2022 年のトップの新しい音楽再生

楽しみのために — 2022 年のトップの新しい音楽再生

ついに!私の 2022 年のトップ ニューミュージック プレイへようこそ。私は毎年これを共有して、友達とつながります。

ヒーズ・オール・アイヴ・ガット

ヒーズ・オール・アイヴ・ガット

あなたの心をチェックしてください。私たちの心はしばしば迷います。

Language