首页 > 解决方案 > 如果路径相同但参数不同,React-Router 不接收道具?

问题描述

我有一条路/player/:id/

如果我从 say 导航/player/12/player/13它会出错,例如:cannot find foo of undefined. 但是,如果我从不同的路径导航/heroes/100/player/12它会加载正常。

我的怀疑是,当我从同一路由链接但参数不同时,新页面不会调用我的 useEffect 或 setState 挂钩。

我觉得我在这里遗漏了一些基本的东西,但我无法弄清楚。如果我的怀疑是正确的,有谁知道我可以如何强制我的组件在从同一路线但不同的参数加载页面之前使用我的 UseEffect 和 UseState 钩子?

参数是正确的,它在 url 栏中显示正确的 id。如果我刷新页面它会加载正常,但如果我点击链接它会出错Cannot read property 'hero_id' of undefined

谢谢

语境:

playedAgainst.map(player => <Link key={Math.random()} to=
{"/players/" + props.invertedPlayers[player]}> <span> {player} </span></Link>

每次迭代都会创建一个带有链接的新玩家名称。当我单击该链接时,它显示所有“无法读取未定义的属性 hero_id”。但是,当我刷新页面时,它加载正常。我 100% 确定链接路径是正确的。我在通向 Player 组件的不同组件中使用了完全相同的代码。

(Math.random 绝对是草率的,我会删除它!)

        <Header />
        <Switch>
          <Route exact path="/">
            <Search players={this.state.players} />
            <GameList players={this.state.players} data={this.state.games} />
            <Footer />
          </Route>
          <Route exact path="/players/:id">
            <Player players={this.state.players} invertedPlayers = {_.invert(this.state.players)} />
          </Route>
          <Route exact path="/heroes/:id">
            <Heroes players={this.state.players} invertedPlayers = {_.invert(this.state.players)} />
          </Route>
        </Switch>
        </Router>

编辑 -

我在我的 Players 组件中添加了以下钩子。

  useEffect(() => {
    console.log('useEffect fired');
}, [])

当我从 1 个 id 转到另一个(相同的路线,不同的参数)时,useEffect 钩子没有触发。

似乎我需要让我的 useEffect 在遵循具有不同 ID 的相同路线时触发。

通过 useParams() 访问我的参数:

let { id } = useParams();
  const [player, setPlayerData] = useState({ data: null, image: null });
  useEffect(() => {
    const fetchData = async () => {
      const response1 = await axios(`/api/players/${id}`);
      const response2 = await axios(`/api/saveImage/${id}`)
      setPlayerData({ data: response1.data, image: response2.data });
    };
    fetchData();
  }, []);

编辑 2 -

将 ID 添加到 useEffect,但由于某种原因,useEffect 仍未重新运行:

let { id } = useParams();
  const [player, setPlayerData] = useState({ data: null, image: null });
  useEffect(() => {
    const fetchData = async () => {
      const response1 = await axios(`/api/players/${id}`);
      const response2 = await axios(`/api/saveImage/${id}`)
      setPlayerData({ data: response1.data, image: response2.data });
    };
    fetchData();
  }, [id]);

编辑 3 -

更多上下文,希望这会有所帮助:

一旦组件加载,它就会从 API 中提取数据以加载到组件中。这工作正常。当我单击一条到同一路线但参数不同的 ling 时,用于提取数据的 useEffect 挂钩不会运行。

const Player = (props) => {
  let { id } = useParams();
  const [player, setPlayerData] = useState({ data: null, image: null });
  useEffect(() => {
    const fetchData = async () => {
      const response1 = await axios(`/api/players/${id}`);
      const response2 = await axios(`/api/saveImage/${id}`)
      setPlayerData({ data: response1.data, image: response2.data });
    };
    fetchData();
  }, [id]);

  useEffect(() => {
    console.log('count changed');
}, [])

  console.log('test')
    return (
        <div className="historyContainer">
...............

{player.data && player.data.map((game, i) => {
    const heroIdOfPlayer = game.players.find(p => p.account_id === +id).hero_id; 
    const teamOfPro = game.players.find(p => p.hero_id === +heroIdOfPlayer).team;

“.......”下面的部分Cannot read property 'hero_id' of undefined是来自哪里,只有在点击链接时才会发生。

再往下几行:

{playedAgainst ?
            playedAgainst.map(player => <Link key={Math.random()} to={"/players/" + props.invertedPlayers[player]}><span> {player} </span></Link>)
            : ""}

这就是每个链接的生成方式。路径是正确的。如果我按照它会说的路径Cannot read property 'hero_id' of undefined,但是当我刷新页面时它会加载正常。

编辑 - 4

添加我的 App 组件以防有帮助:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      games: [],
      players: {},
    };
  }



  componentDidMount() {
    ReactGA.pageview(window.location.pathname)
    this.loadGames();
    this.loadPlayers();
    this.interval = setInterval(() => {
      this.loadGames();
    }, 5000);

  }

  componentWillUnmount() {
    this.loadGames();
    clearInterval(this.interval);
  }

  async loadGames() {
    const response = await fetch('/api/games');
    const myJson = await response.json();
    const sortedJson = myJson.sort((a, b) =>
      a.spectators > b.spectators ? -1 : 1,
    );
    this.setState({ games: sortedJson });
  }

  async loadPlayers() {
    const response = await fetch('/api/playersList');
    const myJson = await response.json();
    this.setState({ players: myJson });
  }

  render() {
    return (
      <Router history={history}>
        <Header />
        <Switch>
          <Route exact path="/">
            <Search players={this.state.players} />
            <GameList players={this.state.players} data={this.state.games} />
            <Footer />
          </Route>
          <Route exact path="/players/:id">
            <Player players={this.state.players} invertedPlayers = {_.invert(this.state.players)} />
          </Route>
          <Route exact path="/heroes/:id">
            <Heroes players={this.state.players} invertedPlayers = {_.invert(this.state.players)} />
          </Route>
        </Switch>
        </Router>
    );
  }
}


ReactDOM.render(<App />, document.getElementById('app'));

标签: javascriptreactjsreact-router

解决方案


在您的useEffect钩子中,将更改的道具作为依赖项传递,即

useEffect(..., [id])

这将确保useEffect每次id更改时都运行,此时的问题是您通过了[],这意味着useEffect在首次安装组件时只会运行一次。


推荐阅读