我正在基于来自反应路由器4的match.params
显示页面。出于某种原因,一些函数运行3次,这使我前2次未定义,第三次是我想要的结果。 / p>
所以我有这个Show组件,它包含来自主组件的道具“projects”。在这个show组件中,我在数组上执行find函数,其中包含props项目。这必须将project.id
等级的1项返回match.params.id
。这很好,如果我通过单击按钮(通过应用程序)访问页面,我会得到包含正确项目和属性的页面(例如project.name
)。但是如果我在浏览器中使用URL进行重新加载或访问页面,则会收到错误消息,指出属性名称未定义。如果我查看控制台,我会看到我的console.logs被激活了3次。就像我说的那样,前两个是未定义的,第三个是给我想要的结果。我猜前两个导致了我得到的错误。
我的显示组件
import React from 'react'
import { Button } from 'reactstrap'
const Show = ({match, projects}) => {
let project = projects.find((project) => {
//Return project with the id equel to the match.params.id
return project.id == match.params.id;
});
//Both these console.logs runs 3 times when visiting a link by url
console.log(project); //this one gives me 2 times undefined, third time is the right item
console.log(match.params.id)
return(
<div className="container p-40">
<div className="projects-header">
{/* If I echo project.name it will gives me 'cannot read property 'name' of undefined' */}
<h2>Project '{match.params.id}' {/* {project.name} */}</h2>
<Button className="btn btn-primary" onClick={() => console.log('save')}>Save</Button>
</div>
<div className="project-edit">
</div>
</div>
);
};
export default Show;
父组件中的路由
<Route exact path="/projects/show/:id" render={(props) => <Show {...props} projects={this.state.projects} />} />
有人为这个问题提供了很好的解决方案吗?我发现这是一个问题,我的用户无法通过网址路由。我不知道为什么我的show组件会通过url / reload激发3次。
编辑(添加父组件):
//Import react
import React, { Component } from 'react';
//Import custom components
import Sidebar from './components/js/Sidebar'
import Dashboard from './components/js/Dashboard'
import Projects from './components/js/Projects'
import Show from './components/js/projects/Show'
//Import styles
import './App.css';
//3rd party deps
import { BrowserRouter as Router, Route } from "react-router-dom";
import axios from 'axios'
class App extends Component {
constructor() {
super();
this.state = {
//Times / Time tracking
times: [],
timer: false,
currentTimer: 0,
//Current task
currentTask: {
id: 3,
title: '',
project_id: {
id: '',
name: '',
color: ''
},
date: '',
time_total: ''
},
//Projects
projects: []
}
this.addTask = this.addTask.bind(this);
this.startTimer = this.startTimer.bind(this);
this.stopTimer = this.stopTimer.bind(this);
this.addProject = this.addProject.bind(this);
}
addTask = (task) => {
let newArray = this.state.times.slice();
newArray.push(task);
this.setState({times: newArray, currentTimer: 0, timer: false});
clearInterval(this.timerID);
}
addProject = (project) => {
let newArray = this.state.projects.slice();
newArray.push(project);
this.setState({ projects: newArray });
}
startTimer() {
let sec = this.state.currentTimer;
const start = Date.now();
this.setState({ timer: true });
this.timerID = setInterval(() => {
let time = new Date() - (start - sec * 1000);
this.setState({ currentTimer: Math.round(time / 1000)});
}, 1000);
}
stopTimer() {
this.setState({ timer: false });
console.log('stopped');
clearInterval(this.timerID);
//Clear interval here
}
componentDidMount() {
// Make a request for a user with a given ID
axios.get('/Sample.json')
.then((response) => {
this.setState({times: response.data});
});
axios.get('/Projects.json')
.then((response) => {
this.setState({projects: response.data});
});
}
render() {
return (
<Router>
<div className="page-wrapper">
<Sidebar />
<Route exact path="/" render={() => <Dashboard times={this.state.times} timer={this.state.timer} startTimer={this.startTimer} stopTimer={this.stopTimer} currentTimer={this.state.currentTimer} addTask={this.addTask} />} />
<Route exact path="/projects" render={() => <Projects projects={this.state.projects} addProject={this.addProject} />} />
<Route exact path="/projects/show/:id" render={(props) => <Show {...props} projects={this.state.projects} />} />
</div>
</Router>
);
}
}
export default App;
答案 0 :(得分:1)
看起来当您的组件首次安装时,您将无法获得完全呈现应用所需的数据。
您正在进行API调用,该调用设置调用重新呈现的状态。然后,您将状态type
传递给show组件。因此,当您的show组件首次尝试渲染时,它无法访问项目数据,但是当API调用完成并且最终渲染发生时,您将获得项目数据。
在一些条件检查中包装你的find函数,看看是否设置了项目
简单的事情:
projects
答案 1 :(得分:1)
您正在couple of async requests
componentDidMount
中App.js
,因此当您重新加载时,这两个请求都会被触发,并且可以在不同时间返回响应,因此{{1触发调用导致渲染被称为3 two setState
。
在times(1 at initial render and 2 after setStates)
,项目是一个空数组,因此您在initial render
之后的第一次获得undefined
。
可能会发生find
在它之后加载,导致setState调用,此时Sample.json
是一个空数组,因此projects
在子项中未定义
现在加载project
时,Projects.json
数组包含数组,项目将被定义
因此您需要为projects
prop
project
如果您想从项目中使用多个属性,可以将它们解构为
return(
<div className="container p-40">
<div className="projects-header">
{/* If I echo project.name it will gives me 'cannot read property 'name' of undefined' */}
<h2>Project '{match.params.id}' {project && project.name} */}</h2>
<Button className="btn btn-primary" onClick={() => console.log('save')}>Save</Button>
</div>
<div className="project-edit">
</div>
</div>
);
P.S。请注意,这仅适用于一个级别的嵌套