我有这个基于类的组件,它具有来自父级的projects
道具。在初始渲染时,prop为null。这将在父组件的lifecyclemethode中的一些调用之后设置。但是因为这需要一些时间,我的子组件上的this.props.projects
一开始就为空。因此,如果我在我的子组件中设置一个状态(null),并且我尝试将状态设置为this.props.projects
,我会得到null,因为我猜道道尚未加载。
现在我做一个秒的setTimeout来接收道具并设置状态。但我认为这不是最佳解决方案。我怎样才能更好地做到这一点?
import React from 'react'
import { Button } from 'reactstrap'
class Show extends React.Component {
constructor(props) {
super(props);
this.state = {
project: null
}
this.run = this.run.bind(this);
}
componentWillMount() {
this.run();
}
run() {
setTimeout(() => {
let project = this.props.projects.find((project) => {
//Return project with the id equel to the match.params.id
return project.id == this.props.match.params.id;
});
this.setState({project: project});
console.log(this.state.project);
}, 1000);
}
render() {
return(
<div className="container p-40">
{this.state.project && this.state.project.name}
</div>
)
}
}
export default Show;
如果我没有在this.run
函数上设置超时,我会返回null。
父
//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/Show2'
//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
}
componentWillMount() {
// 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 :(得分:0)
您可以在componentDidUpdate()中运行this.run()
并检查道具是否已从null更改为设置
componentDidUpdate(prevProps) {
if(this.props.projects !== prevProps.projects){
this.run();
}
}
答案 1 :(得分:0)
因此,似乎有两种情况需要合并:
"/projects/show/:id"
,这会导致<App/>
和<Show/>
组件一个接一个地加载projects
状态<App/>
1}}是一个空数组,因为axios.get('/Projects.json')
尚未完成。完成后,状态会更新,<App/>
会向projects
组件发送新的<Show/>
道具。在这种情况下,您可以使用componentWillReceiveProps(nextProps)
来比较新的和以前的道具并运行this.run()
方法。"/"
或"/projects"
并加载<App/>
组件,过一段时间后,点击左右移动到/projects/show/:id
。在这种情况下,projects
中的<App/>
状态可能已经更新,projects
道具(此时不是空数组)已准备好传递给<Show/>
组件。所以在这种情况下,使用<Show/>
组件的第一次装载和渲染,projects
道具具有包含值的实际数组。您可以使用componentWillMount()
方法处理此问题并在此处运行this.run()
,因为之后不会对道具进行任何更新,componentWillReceiveProps(nextProps)
将不会触发,因为axios.get('/Projects.json')
已经完成很久以前。所以,我建议您处理这两种情况,因为它应该同时使用componentWillMount()
和componentWillReceiveProps(nextProps)
方法并检查projects
道具是否具有以下值:
componentWillMount() {
// check if projects props is not an empty array at initial load
if (this.props.projects.length > 0) {
this.run(this.props.projects);
}
}
componentWillReceiveProps(nextProps) {
// check if new and old projects props are different
if (nextProps.projects.length > 0 && (nextProps.projects !== this.props.projects)) {
this.run(nextProps.projects);
}
}
// and finally update your run() method
run(projects) {
let project = projects.find((project) => {
return project.id == this.props.match.params.id;
});
this.setState({project: project});
}