从子级到父级组件的回调函数

时间:2020-03-30 06:45:46

标签: reactjs

我正在尝试聊天。但是,当我发送消息时,我需要刷新页面以获取页面上的数据。我要组件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:'ddd@gmail.com',
            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),这就是为什么我不能在一个组件中使用它们。

更新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:'ddd@gmail.com',
            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 个答案:

答案 0 :(得分:2)

在父级中定义回调。从子窗体中提取消息数据,从而分离出发送消息数据的逻辑。父级的回调函数接收消息数据并将其发送,而子级组件的函数则提取表单数据,对其进行格式化,调用在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:'ddd@gmail.com',
            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>
        );
    }
}

更新以包括同步功能

Sync API

Using the Sync API with Javascirpt

更新到父组件:

  • 添加类实例计时器变量以保存间隔计时器引用
  • 创建用于处理同步数据调用的功能
  • 更新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文档,因此可能需要进行一些调整才能按预期工作,或者如果您更喜欢 使用箭头功能等...

答案 1 :(得分:0)

我看不到您尝试在哪里向父级添加sendMessage函数。

您可以通过道具来提供它,为什么不能。

在子组件中,您可以执行以下操作

interface IChildComponentWithSendMessage{
    sendMessage
}

export class ChildComponent extends React.Component<IChildComponentWithSendMessage>

您可以通过道具为您提供messageMethod

您也不必这样做

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

我也认为这可能是您的问题,为什么您不能向子/父组件提供此方法

您可以创建如下功能:

sendMessage = () => {
}