React Native: How to access a variable from parent component in child component?

心不动则不痛 提交于 2021-02-01 05:16:45

问题


i am trying to pass my newsocket variable from my MessagesScreen.js to my ChatScreen.js.

I have been stuck on this point for a while and would appreciate any help possible. What i am trying to achieve is that only one connection gets emitted which i can listen to events on both screen.

The connection is now opened on the messagesScreen. My problem now is if user 1 is on the allmessages screen and user 2 is inside the chat. And user 2 sends user 1 a message, user 1's screen does not automatically update with the last message for the conversation the message was sent to, I need to either scroll to refresh or navigate from one page to the other in order for it to appear.

Here is my code:

PARENT --> messagesScreen.js

function MessagesScreen({navigation}) {
const [posts, setPosts] = useState([]);
const { user } = useAuth();
const [socket, setSocket] = useState(null);

const loadposts = async () => {
const response = await messagesApi.getMessages();// here i am loading all the conversation this user has
setPosts(response.data)
};

useEffect(() => {

newsocket = sockets(user.id); // newsocket is what i am trying to pass to child component
setSocket(newsocket);

loadPosts()

newsocket.on("send_message", (msg) => {
  console.log("messages:", msg);
})

}, []);

return (
<FlatList
    data={posts}
    keyExtractor={(post) => post.id.toString()}
    renderItem={({ item,index }) => (
      <MessagesList
      title={item.Post.title}
        subTitle={item.Messages[0].message}
        onPress={() => navigation.navigate(
                routes.CHAT,{message:item,index,newsocket:socket})}
      />
    )}
  />
)

CHILD ---> chatScreen.js

function ChatScreen({route,navigation,socket}) {  
const [messages, setMessages] = useState([]);
const { user } = useAuth();

  const index = route.params.index;
  const message = route.params.message;
  const newsocket = route.params.newsocket;

  const loadListings = async () => {
  const response = await messagesApi.getConversation(message.id);// here i am loading the messages in that specific conversation
  setMessages(response.data.Messages)
  };

 useEffect(() => {
 loadListings()
 newsocket.emit('subscribe', message.id);

 newsocket.on("send_message", (msg) => {
    console.log("this is the chat messages:", msg);
    setMessages(messages => [msg, ...messages]);
  });
  }, []);

 const onSend = (ConversationId,senderId,receiverId,message) => {

const to = (user.id===route.params.message.user1? 
route.params.message.user2:route.params.message.user1)

socket.emit('message', { to: to, from: user.id, message,ConversationId});

messagesApi.sendMessage({ConversationId,senderId,receiverId,message});
};

return(
 <FlatList
    inverted
    data={messages}
    keyExtractor={(item,index)=>index.toString()}
    extraData={messages} // add this    
    renderItem={({item,index})=>(
        <MessageBubble
        text={item.message}
        mine={item.senderId !== user.id}
        />
    )}
    />
)

socket.js

import io from 'socket.io-client';

const newsocket = (user) => {
let newsocket = io.connect("http://192.168.1.107:9000")

newsocket.on('connect', msg => {
console.log(`waiting for user: ${user} to join a conversation`)
});

newsocket.emit('waiting', user);

return newsocket;
}

export default newsocket;

回答1:


On the MessagesScreen screen you are passing the SOCKET function and not the variable it self . i think you do not need the function . you directly pass the variable and access in chatScreen screen .

MessagesScreen.js

routes.CHAT,{message:item,index,updateView, newsocket})}

chatScreen.js

const newsocket = route.params.newsocket;
 ....

newsocket.emit('subscribe', message.id);  // call like this



回答2:


I would approach this differently.

  1. You can create your socket connection as a shared service in a separate module and simply import that into the relevant components you need. In this shared module you handle connecting/disconnecting and return an existing connection or create a new connection to return.

Quick rough:

// socket-server.ts
import io from 'socket.io-client';

let socket: SocketIOClient.Socket = null;

export const getSocketServer = (): Promise<SocketIOClient.Socket> => {
    return new Promise<SocketIOClient.Socket>(resolve => {
        if (socket) {
            console.info(`returning existing socket: ${socket.id}`);

            return resolve(socket);
        }

        socket = io('http://localhost:4000', {
            autoConnect: false,
        });

        socket.on('connect_error', (err) => {
            console.error(err);
        })

        socket.on('connect', () => {
            console.info(`creating new socket: ${socket.id}`);

            return resolve(socket);
        });

        socket.open();
    })
}

// then in your relevant modules
// module-a.ts
import React, {useEffect, useState} from 'react';
import {getSocketServer} from './../components/socket-server';

const Component = () => {
    useEffect(() => {
        const connect = async () => {
            const socket = await getSocketServer();

            socket.on('hello', (message) => {
                console.info('hello from module A', message);
            });
        }
        connect();
    }, []);

    return (
        <>
            <h2>Module A</h2>
        </>
    )
}

export default Component;
  1. You could maybe also look at creating a Context Provider and share the socket with relevant modules as needed.

Context provides a way to pass data through the component tree without having to pass props down manually at every level.



来源:https://stackoverflow.com/questions/65759907/react-native-how-to-access-a-variable-from-parent-component-in-child-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!