React 子组件到父组件的回调函数

IT技术 reactjs
2021-05-17 12:50:57

我正在尝试聊天。但是当我发送消息时,我需要刷新页面以获取页面上的数据。我必须组件 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>
        );
    }
}

我尝试添加props,但不确定适合它们的位置 有什么建议吗?

更新 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个回答

在父级中定义回调。从child中的form中提取消息数据,拆分出发送消息数据的逻辑。父组件的回调接收消息数据并发送,而子组件的函数则拉取表单数据,对其进行格式化,调用传入 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>
        );
    }
}

更新以包括同步功能

同步API

将同步 API 与 Javascipt 结合使用

更新父组件:

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

我没有看到您尝试向父级添加函数 sendMessage 的位置。

你可以通过 props 提供它,为什么不呢。

在子组件中,你可以做这样的事情

interface IChildComponentWithSendMessage{
    sendMessage
}

export class ChildComponent extends React.Component<IChildComponentWithSendMessage>

你可以通过 props 为你提供 messageMethod

你也不必做

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

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

你可以创建这样的函数:

sendMessage = () => {
}