简体   繁体   English

React Link 在浏览器上更改 URL 但不呈现新内容

[英]React Link changes URL on the browser but doesn't render new content

I am building a chat app and trying to match the id params to render each one on click.I have a RoomList component that maps over the rooms via an endpoint /rooms我正在构建一个聊天应用程序并尝试匹配 id 参数以在单击时呈现每个参数。我有一个 RoomList 组件,它通过端点 /rooms 映射到房间

I then have them linked to their corresponding ID.然后,我将它们链接到相应的 ID。 THe main components are Chatroom.js and RoomList is just the nav主要组件是 Chatroom.js,RoomList 只是导航

import moment from 'moment';
import './App.scss';
import UserInfo from './components/UserInfo';
import RoomList from './components/RoomList';
import Chatroom from './components/Chatroom';
import SendMessage from './components/SendMessage';
import { Column, Row } from "simple-flexbox";
import { Route, Link, Switch } from 'react-router-dom'

function App() {

  const timestamp = Date.now();
  const timeFormatted = moment(timestamp).format('hh:mm');

  const [username, setUsername] = useState('');
  const [loggedin, setLoggedin] = useState(false);

  const [rooms, setRooms] = useState([]);
  const [roomId, setRoomId] = useState(0);

  const handleSubmit = async e => {
    e.preventDefault();
    setUsername(username)
    setLoggedin(true)
  };

  useEffect(() => {
    let apiUrl= `http://localhost:8080/api/rooms/`;
    const makeApiCall = async() => {
      const res = await fetch(apiUrl);
      const data = await res.json();
      setRooms(data);
    };
    makeApiCall();
  }, [])

  const handleSend = (message) => {
    const formattedMessage = { name: username, message, isMine: true};
  }

  return (
    <div className="App">
    
      <Route 
        path="/" 
        render={(routerProps) => (
          (loggedin !== false) ?

            <Row>
              <Column>
                {/*<Chatroom roomId={roomId} messages={messages} isMine={isMine}/>*/}
                
              </Column>
            </Row>
          :
          <form onSubmit={handleSubmit}>
            <label htmlFor="username">Username: </label>
            <input
              type="text"
              value={username}
              placeholder="enter a username"
              onChange={({ target }) => setUsername(target.value)}
            />
           <button type="submit">Login</button>
          </form>
        )} 
      />
      
    <Switch>

      <Route 
        exact 
        path="/:id" 
        render={(routerProps) => (
          <Row>
            <Column>
              <UserInfo username={username} time={timeFormatted}/>
              <RoomList rooms={rooms}/>
            </Column>
            <Column>
              <Chatroom {...routerProps} roomId={roomId}/>
              <SendMessage onSend={handleSend}/>
            </Column>
          </Row>
        )}
      />
      </Switch>
     
    </div>
  );
}

export default App;

RoomList.js RoomList.js

import { Row } from "simple-flexbox";

const RoomList = (props) => {
    return (
        <div className="RoomList">
            <Row wrap="false">
                {
                    props.rooms.map((room, index) => {
                        return (
                            <Link to={`/${room.id}`} key={index}>{room.id} {room.name}</Link>
                        )
                    })
                }
            </Row>
        </div>
    )
}

export default RoomList;

Chatroom.js this is the main component that should render based on the ID Chatroom.js这是应该根据 ID 呈现的主要组件

import Message from './Message';
import { Link } from 'react-router-dom'

const Chatroom = (props) => {
    const [roomId, setRoomId] = useState(0);
    const [name, setName] = useState('Roomname')
    const [messages, setMessages] = useState([]);

    useEffect(() => {
    let apiUrl= `http://localhost:8080/api/rooms/`;
    const id = props.match.params.id;
    const url = `${apiUrl}${id}`;
    const makeApiCall = async () => {
      const res = await fetch(url);
      const data = await res.json();
      setRoomId(data.id);
      setUsers(data.users)
      setName(data.name)
    };
    makeApiCall();
  }, []);

  useEffect(() => {
    const id = props.match.params.id;
    const url = `http://localhost:8080/api/rooms/${id}/messages`;
    const makeApiCall = async() => {
      const res = await fetch(url);
      const data = await res.json();
      setMessages(data);
    };
    makeApiCall();
  }, [])

    return (
        <div className="Chatroom">
            {name}
        </div>
    )
}

export default Chatroom;```

when I click on the links I want the change to refresh the new content but it wont? any ideas why ? thank you in advance!

Notice that your functional component named App does not have any dependencies and that is fine since data should just be fetched once, on mount.请注意,名为 App 的功能组件没有任何依赖关系,这很好,因为数据应该在挂载时只获取一次。 However, on ChatRoom we want a new fetch everytime that roomId changes.但是,在 ChatRoom 上,我们希望每次 roomId 更改时都进行新的获取。

First thing we could do here is adding props.match.params.id directly into our initial state.我们可以在这里做的第一件事是将 props.match.params.id 直接添加到我们的初始 state 中。

 const [roomId, setRoomId] = useState(props.match.params.id); // set up your initial room id here.

Next we can add an effect that checks if roomId needs updating whenever props change.接下来我们可以添加一个效果来检查 roomId 是否需要在 props 更改时更新。 Like this:像这样:

useEffect(()=>{
    if(roomId !== props.match.params.id) {
         setRoomId(props.match.params.id)
    }
}, [props])

Now we use roomId as our state for the api calls and add it in the brackets (making react aware that whenever roomId changes, it should run our effect again).现在我们使用 roomId 作为 api 调用的 state 并将其添加到括号中(让反应知道,每当 roomId 更改时,它应该再次运行我们的效果)。

 useEffect(() => {
        let url = "http://localhost:8080/api/rooms/" + roomId; // add room id here
        const makeApiCall = async () => {
          const res = await fetch(url);
          const data = await res.json();
          setUsers(data.users)
          setName(data.name)
         };
         makeApiCall();
    }, [roomId]); // very important to add room id to your dependencies as well here.


   useEffect(() => {
    const url = `http://localhost:8080/api/rooms/${roomId}/messages`; // add room id here as well
    const makeApiCall = async() => {
      const res = await fetch(url);
      const data = await res.json();
      setMessages(data);
    };
    makeApiCall();
   }, [roomId]) // very important to add room id to your dependencies as well here.

I believe that it should work.我相信它应该起作用。 But let me build my answer upon this: When mounted, meaning that this is the first time that the ChatRoom is rendered, it will go through your useEffect and fetch data using roomId as the initial state that we setup as props.match.params.id.但是,让我在此基础上构建我的答案:安装后,这意味着这是第一次渲染 ChatRoom,它将通过您的 useEffect go 并使用 roomId 作为我们设置为 props.match.params 的初始 state 获取数据。 ID。

Without dependencies, he is done and would never fetch again.没有依赖关系,他就完成了,永远不会再获取。 It would do it once and that's it.它会做一次,就是这样。 However, by adding the dependency, we advise react that it would watch out for roomId changes and if they do, it should trigger the function again.但是,通过添加依赖项,我们建议 react 会注意 roomId 更改,如果发生更改,它应该再次触发 function。 It is VERY IMPORTANT that every variable inside your useEffect is added to your brackets.将 useEffect 中的每个变量都添加到括号中是非常重要的。 There is eslint for it and it is very useful.它有 eslint,它非常有用。 Have a look at this post.看看这个帖子。 It helped me a lot.这对我帮助很大。

https://overreacted.io/a-complete-guide-to-useeffect/ https://overreacted.io/a-complete-guide-to-useeffect/

Let me know if it works and ask me if there is still doubts.让我知道它是否有效,并询问我是否仍有疑问。 =) =)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM