tag react has div corresponding closing change reactjs

reactjs - react - jsx element div has no corresponding closing tag



¿Cómo desplazarse al fondo en reaccionar? (15)

Quiero crear un sistema de chat y desplazarme automáticamente hacia la parte inferior cuando ingrese a la ventana y cuando lleguen nuevos mensajes. ¿Cómo se desplaza automáticamente hacia la parte inferior de un contenedor en React?


  1. Consulte su contenedor de mensajes.

    <div ref={(el) => { this.messagesContainer = el; }}> YOUR MESSAGES </div>

  2. Encuentre su contenedor de mensajes y haga que su atributo scrollTop igual a scrollHeight :

    scrollToBottom = () => { const messagesContainer = ReactDOM.findDOMNode(this.messagesContainer); messagesContainer.scrollTop = messagesContainer.scrollHeight; };

  3. Evoque el método anterior en componentDidMount y componentDidUpdate .

    componentDidMount() { this.scrollToBottom(); } componentDidUpdate() { this.scrollToBottom(); }

Así es como estoy usando esto en mi código:

export default class StoryView extends Component { constructor(props) { super(props); this.scrollToBottom = this.scrollToBottom.bind(this); } scrollToBottom = () => { const messagesContainer = ReactDOM.findDOMNode(this.messagesContainer); messagesContainer.scrollTop = messagesContainer.scrollHeight; }; componentDidMount() { this.scrollToBottom(); } componentDidUpdate() { this.scrollToBottom(); } render() { return ( <div> <Grid className="storyView"> <Row> <div className="codeView"> <Col md={8} mdOffset={2}> <div ref={(el) => { this.messagesContainer = el; }} className="chat"> { this.props.messages.map(function (message, i) { return ( <div key={i}> <div className="bubble" > {message.body} </div> </div> ); }, this) } </div> </Col> </div> </Row> </Grid> </div> ); } }


Como mencionó Tushar, puede mantener una división ficticia en la parte inferior de su chat:

render () { return ( <div> <div className="MessageContainer" > <div className="MessagesList"> {this.renderMessages()} </div> <div style={{ float:"left", clear: "both" }} ref={(el) => { this.messagesEnd = el; }}> </div> </div> </div> ); }

y luego desplácese a él cada vez que se actualice su componente (es decir, estado actualizado a medida que se agregan nuevos mensajes):

scrollToBottom = () => { this.messagesEnd.scrollIntoView({ behavior: "smooth" }); } componentDidMount() { this.scrollToBottom(); } componentDidUpdate() { this.scrollToBottom(); }

Estoy usando el método estándar Element.scrollIntoView aquí.



Creé un elemento vacío al final de los mensajes y me desplacé a ese elemento. No es necesario hacer un seguimiento de los árbitros.


Gracias a @enlitement

debemos evitar usar findDOMNode , podemos usar refs para hacer un seguimiento de los componentes

render() { ... return ( <div> <div className="MessageList" ref={(div) => { this.messageList = div; }} > { messageListContent } </div> </div> ); } scrollToBottom() { const scrollHeight = this.messageList.scrollHeight; const height = this.messageList.clientHeight; const maxScrollTop = scrollHeight - height; this.messageList.scrollTop = maxScrollTop > 0 ? maxScrollTop : 0; } componentDidUpdate() { this.scrollToBottom(); }

referencia:


Me gusta hacerlo de la siguiente manera.

componentDidUpdate(prevProps, prevState){ this.scrollToBottom(); } scrollToBottom() { const {thing} = this.refs; thing.scrollTop = thing.scrollHeight - thing.clientHeight; } render(){ return( <div ref={`thing`}> <ManyThings things={}> </div> ) }


No use findDOMNode

class MyComponent extends Component { componentDidMount() { this.scrollToBottom(); } componentDidUpdate() { this.scrollToBottom(); } scrollToBottom() { this.el.scrollIntoView({ behavior: ''smooth'' }); } render() { return <div ref={el => { this.el = el; }} /> } }


Puede usar ref para realizar un seguimiento de los componentes.

Si conoce una manera de configurar la ref de un componente individual (el último), ¡publique!

Esto es lo que encontré que funcionó para mí:

class ChatContainer extends React.Component { render() { const { messages } = this.props; var messageBubbles = messages.map((message, idx) => ( <MessageBubble key={message.id} message={message.body} ref={(ref) => this[''_div'' + idx] = ref} /> )); return ( <div> {messageBubbles} </div> ); } componentDidMount() { this.handleResize(); // Scroll to the bottom on initialization var len = this.props.messages.length - 1; const node = ReactDOM.findDOMNode(this[''_div'' + len]); if (node) { node.scrollIntoView(); } } componentDidUpdate() { // Scroll as new elements come along var len = this.props.messages.length - 1; const node = ReactDOM.findDOMNode(this[''_div'' + len]); if (node) { node.scrollIntoView(); } } }


Si desea hacer esto con React Hooks, puede seguir este método. Para un divino div se ha colocado en la parte inferior del chat. useRef Hook se usa aquí.

Referencia de la API de Hooks: https://reactjs.org/docs/hooks-reference.html#useref

import React, { useEffect, useRef } from ''react''; const ChatView = ({ ...props }) => { const el = useRef(null); useEffect(() => { el.current.scrollIntoView({ block: ''end'', behavior: ''smooth'' }); }); return ( <div> <div className="MessageContainer" > <div className="MessagesList"> {this.renderMessages()} </div> <div id={''el''} ref={el}> </div> </div> </div> ); }


Solo quiero actualizar la respuesta para que coincida con el nuevo method React.createRef() , pero es básicamente lo mismo, solo tenga en cuenta la propiedad current en la referencia creada:

class Messages extends React.Component { messagesEndRef = React.createRef() componentDidMount () { this.scrollToBottom() } componentDidUpdate () { this.scrollToBottom() } scrollToBottom = () => { this.messagesEnd.current.scrollIntoView({ behavior: ''smooth'' }) } render () { const { messages } = this.props return ( <div> {messages.map(message => <Message key={message.id} {...message} />)} <div ref={this.messagesEndRef} /> </div> ) } }

ACTUALIZAR:

Ahora que los ganchos están disponibles, estoy actualizando la respuesta para agregar el uso de los ganchos useRef y useEffect , lo real que hace la magia (React scrollIntoView y scrollIntoView DOM) sigue siendo el mismo:

import React, { useEffect, useRef } from ''react'' const Messages = ({ messages }) => { const messagesEndRef = useRef(null) const scrollToBottom = () => { messagesEndRef.current.scrollIntoView({ behavior: "smooth" }) } useEffect(scrollToBottom, [messages]); return ( <div> {messages.map(message => <Message key={message.id} {...message} />)} <div ref={this.messagesEndRef} /> </div> ) }

También hizo un códigoandbox (muy básico) si desea verificar el comportamiento https://codesandbox.io/s/scrolltobottomexample-f90lz


Versión completa (mecanografiada):

import * as React from ''react'' export class DivWithScrollHere extends React.Component<any, any> { loading:any = React.createRef(); componentDidMount() { this.loading.scrollIntoView(false); } render() { return ( <div ref={e => { this.loading = e; }}> <LoadingTile /> </div> ) } }


gracias ''metakermit'' por su buena respuesta, pero creo que podemos hacerlo un poco mejor, para desplazarnos hacia abajo, deberíamos usar esto:

scrollToBottom = () => { this.messagesEnd.scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" }); }

pero si desea desplazarse hacia arriba, debe usar esto:

scrollToTop = () => { this.messagesEnd.scrollIntoView({ behavior: "smooth", block: "start", inline: "nearest" }); }

y estos códigos son comunes:

componentDidMount() { this.scrollToBottom(); } componentDidUpdate() { this.scrollToBottom(); } render () { return ( <div> <div className="MessageContainer" > <div className="MessagesList"> {this.renderMessages()} </div> <div style={{ float:"left", clear: "both" }} ref={(el) => { this.messagesEnd = el; }}> </div> </div> </div> ); }


react-scrollable-feed se desplaza automáticamente hacia abajo hasta el último elemento si el usuario ya estaba en la parte inferior de la sección desplazable. De lo contrario, dejará al usuario en la misma posición. Creo que esto es bastante útil para los componentes del chat :)

Creo que las otras respuestas aquí forzarán el desplazamiento cada vez sin importar dónde esté la barra de desplazamiento. El otro problema con scrollIntoView es que desplazará toda la página si su div desplazable no estaba a la vista.

Se puede usar así:

import * as React from ''react'' import ScrollableFeed from ''react-scrollable-feed'' class App extends React.Component { render() { const messages = [''Item 1'', ''Item 2'']; return ( <ScrollableFeed> {messages.map((message, i) => <div key={i}>{message}</div>)} </ScrollableFeed> ); } }

Solo asegúrese de tener un componente de envoltura con una height específica o height max-height

Descargo de responsabilidad: soy el propietario del paquete


Ejemplo de trabajo

Puede usar el método DOM scrollIntoView para hacer que un componente sea visible en la vista.

Para esto, al renderizar el componente, simplemente proporcione una ID de referencia para el elemento DOM utilizando el atributo ref . Luego use el método scrollIntoView en el ciclo de vida de componentDidMount . Solo estoy poniendo un código de muestra funcional para esta solución. El siguiente es un componente que representa cada vez que se recibe un mensaje. Debe escribir código / métodos para representar este componente.

class ChatMessage extends Component { scrollToBottom = (ref) => { this.refs[ref].scrollIntoView({ behavior: "smooth" }); } componentDidMount() { this.scrollToBottom(this.props.message.MessageId); } render() { return( <div ref={this.props.message.MessageId}> <div>Message content here...</div> </div> ); } }

Aquí this.props.message.MessageId es la ID única del mensaje de chat particular que se pasa como props


import React, {Component} from ''react''; export default class ChatOutPut extends Component { constructor(props) { super(props); this.state = { messages: props.chatmessages }; } componentDidUpdate = (previousProps, previousState) => { if (this.refs.chatoutput != null) { this.refs.chatoutput.scrollTop = this.refs.chatoutput.scrollHeight; } } renderMessage(data) { return ( <div key={data.key}> {data.message} </div> ); } render() { return ( <div ref=''chatoutput'' className={classes.chatoutputcontainer}> {this.state.messages.map(this.renderMessage, this)} </div> ); } }